├── .github ├── tiny-world.app │ └── Contents │ │ ├── Info.plist │ │ └── Resources │ │ └── tiny-world.icns └── workflows │ ├── publish.yml │ ├── release.yml │ ├── test-release.yml │ ├── tests-wasm.yml │ └── tests.yml ├── .gitignore ├── CHANGELOG.md ├── INSTALL.md ├── LICENSE ├── README.md ├── artwork └── sprites │ └── paper │ ├── buttons_52x52 │ └── button │ │ ├── button.json │ │ ├── button.png │ │ ├── button.xcf │ │ ├── button_disabled.png │ │ └── button_pressed.png │ ├── flat_48x24 │ ├── border │ │ ├── border_inner.json │ │ ├── border_inner.png │ │ ├── border_inner_01.png │ │ ├── border_inner_02.png │ │ ├── border_inner_03.png │ │ ├── border_inner_04.png │ │ ├── border_inner_05.png │ │ ├── border_inner_06.png │ │ ├── border_inner_07.png │ │ ├── border_inner_08.png │ │ ├── border_inner_09.png │ │ ├── border_inner_10.png │ │ ├── border_inner_11.png │ │ ├── border_inner_12.png │ │ ├── border_inner_13.png │ │ ├── border_inner_14.png │ │ ├── border_inner_15.png │ │ ├── border_multitile │ │ │ ├── border_inner.json │ │ │ ├── border_inner.png │ │ │ ├── border_inner.xcf │ │ │ ├── border_outer.json │ │ │ ├── border_outer.png │ │ │ └── border_outer.xcf │ │ ├── border_outer.json │ │ ├── border_outer.png │ │ ├── border_outer_01.png │ │ ├── border_outer_02.png │ │ ├── border_outer_03.png │ │ ├── border_outer_04.png │ │ ├── border_outer_05.png │ │ ├── border_outer_06.png │ │ ├── border_outer_07.png │ │ ├── border_outer_08.png │ │ ├── border_outer_09.png │ │ ├── border_outer_10.png │ │ ├── border_outer_11.png │ │ ├── border_outer_12.png │ │ ├── border_outer_13.png │ │ ├── border_outer_14.png │ │ └── border_outer_15.png │ ├── bridge │ │ ├── bridge.json │ │ ├── bridge.png │ │ ├── bridge_01.png │ │ ├── bridge_02.png │ │ ├── bridge_03.png │ │ ├── bridge_04.png │ │ ├── bridge_05.png │ │ ├── bridge_06.png │ │ ├── bridge_07.png │ │ ├── bridge_08.png │ │ ├── bridge_09.png │ │ ├── bridge_10.png │ │ ├── bridge_11.png │ │ ├── bridge_12.png │ │ ├── bridge_13.png │ │ ├── bridge_14.png │ │ ├── bridge_15.png │ │ └── bridge_multitile │ │ │ ├── bridge.json │ │ │ ├── bridge.png │ │ │ └── bridge.xcf │ ├── building_base │ │ ├── building_base.json │ │ ├── building_base.png │ │ ├── building_base_01.png │ │ ├── building_base_02.png │ │ ├── building_base_03.png │ │ ├── building_base_04.png │ │ ├── building_base_05.png │ │ ├── building_base_06.png │ │ ├── building_base_07.png │ │ ├── building_base_08.png │ │ ├── building_base_09.png │ │ ├── building_base_10.png │ │ ├── building_base_11.png │ │ ├── building_base_12.png │ │ ├── building_base_13.png │ │ ├── building_base_14.png │ │ ├── building_base_15.png │ │ └── building_base_multitile │ │ │ ├── building_base.json │ │ │ ├── building_base.png │ │ │ └── building_base.xcf │ ├── desert │ │ ├── desert.json │ │ ├── desert.png │ │ ├── desert_01.png │ │ ├── desert_02.png │ │ ├── desert_03.png │ │ ├── desert_04.png │ │ ├── desert_05.png │ │ ├── desert_06.png │ │ ├── desert_07.png │ │ ├── desert_08.png │ │ ├── desert_09.png │ │ ├── desert_10.png │ │ ├── desert_11.png │ │ ├── desert_12.png │ │ ├── desert_13.png │ │ ├── desert_14.png │ │ ├── desert_15.png │ │ └── desert_multitile │ │ │ ├── desert.json │ │ │ ├── desert.png │ │ │ └── desert.xcf │ ├── food │ │ ├── food.png │ │ └── food.xcf │ ├── hills │ │ ├── hills.json │ │ ├── hills.png │ │ ├── hills.xcf │ │ ├── hills_v2.png │ │ ├── hills_v3.png │ │ ├── hills_v4.png │ │ ├── hills_v5.png │ │ └── hills_v6.png │ ├── path │ │ ├── path.json │ │ ├── path.png │ │ ├── path_01.png │ │ ├── path_02.png │ │ ├── path_03.png │ │ ├── path_04.png │ │ ├── path_05.png │ │ ├── path_06.png │ │ ├── path_07.png │ │ ├── path_08.png │ │ ├── path_09.png │ │ ├── path_10.png │ │ ├── path_11.png │ │ ├── path_12.png │ │ ├── path_13.png │ │ ├── path_14.png │ │ ├── path_15.png │ │ └── path_multitile │ │ │ ├── path.json │ │ │ ├── path.png │ │ │ └── path.xcf │ ├── stones │ │ ├── stones.png │ │ └── stones.xcf │ ├── water │ │ ├── water.json │ │ ├── water.png │ │ ├── water_01.png │ │ ├── water_02.png │ │ ├── water_03.png │ │ ├── water_04.png │ │ ├── water_05.png │ │ ├── water_06.png │ │ ├── water_07.png │ │ ├── water_08.png │ │ ├── water_09.png │ │ ├── water_10.png │ │ ├── water_11.png │ │ ├── water_12.png │ │ ├── water_13.png │ │ ├── water_14.png │ │ ├── water_15.png │ │ └── water_multitile │ │ │ ├── water.json │ │ │ ├── water.png │ │ │ └── water.xcf │ └── wood │ │ ├── wood.png │ │ └── wood.xcf │ ├── full_48x48 │ ├── buildable │ │ ├── buildable.png │ │ └── buildable.xcf │ ├── bulldoze │ │ ├── bulldoze.png │ │ └── bulldoze.xcf │ ├── castle │ │ ├── castle.png │ │ ├── castle.xcf │ │ ├── tower.png │ │ ├── tower.xcf │ │ └── tower_large.xcf │ ├── church │ │ ├── church.png │ │ └── church.xcf │ ├── farm │ │ ├── farm.png │ │ └── farm.xcf │ ├── fisherman │ │ ├── fisherman.png │ │ └── fisherman.xcf │ ├── lumberjack │ │ ├── lumberjack.png │ │ └── lumberjack.xcf │ ├── mason │ │ ├── mason.png │ │ └── mason.xcf │ ├── monastery │ │ ├── monastery.png │ │ └── monastery.xcf │ ├── plains │ │ ├── plains.json │ │ ├── plains.png │ │ ├── plains_01.png │ │ ├── plains_02.png │ │ ├── plains_03.png │ │ ├── plains_04.png │ │ ├── plains_05.png │ │ ├── plains_06.png │ │ ├── plains_07.png │ │ ├── plains_08.png │ │ ├── plains_09.png │ │ ├── plains_10.png │ │ ├── plains_11.png │ │ ├── plains_12.png │ │ ├── plains_13.png │ │ ├── plains_14.png │ │ ├── plains_15.png │ │ ├── plains_15.xcf │ │ ├── plains_15_r1.png │ │ ├── plains_15_r2.png │ │ ├── plains_15_r3.png │ │ ├── plains_15_r4.png │ │ └── plains_multitile_off │ │ │ ├── plains.json │ │ │ ├── plains.png │ │ │ ├── plains.xcf │ │ │ ├── plains_base.png │ │ │ └── plains_base.xcf │ ├── rock │ │ ├── rock.json │ │ ├── rock_01.png │ │ ├── rock_01.xcf │ │ ├── rock_02.png │ │ └── rock_02.xcf │ ├── shepherd │ │ ├── shepherd.png │ │ └── shepherd.xcf │ ├── tree │ │ ├── tree.json │ │ ├── tree_c_01.png │ │ ├── tree_c_01.xcf │ │ ├── tree_c_02.png │ │ ├── tree_c_02.xcf │ │ ├── tree_d_01.png │ │ ├── tree_d_01.xcf │ │ ├── tree_d_02.png │ │ └── tree_d_02.xcf │ ├── unknown │ │ ├── unknown.json │ │ ├── unknown.png │ │ └── unknown.xcf │ ├── warehouse │ │ ├── warehouse.json │ │ ├── warehouse.png │ │ ├── warehouse.xcf │ │ └── warehouse_S.png │ ├── watermill │ │ ├── watermill.json │ │ ├── watermill.xcf │ │ ├── watermill_E.png │ │ ├── watermill_N.png │ │ ├── watermill_S.png │ │ └── watermill_W.png │ └── windmill │ │ ├── windmill.png │ │ └── windmill.xcf │ ├── half_48x36 │ ├── fence │ │ ├── fence.json │ │ ├── fence.png │ │ ├── fence.xcf │ │ ├── fence_01.png │ │ ├── fence_02.png │ │ ├── fence_03.png │ │ ├── fence_04.png │ │ ├── fence_05.png │ │ ├── fence_06.png │ │ ├── fence_07.png │ │ ├── fence_08.png │ │ ├── fence_09.png │ │ ├── fence_10.png │ │ ├── fence_11.png │ │ ├── fence_12.png │ │ ├── fence_13.png │ │ ├── fence_14.png │ │ └── fence_15.png │ ├── field │ │ ├── field.png │ │ └── field.xcf │ ├── pasture │ │ ├── pasture.json │ │ ├── pasture.png │ │ ├── pasture.xcf │ │ ├── pasture_v2.png │ │ └── pasture_v3.png │ └── warning_marker │ │ ├── warning_marker.json │ │ ├── warning_marker.png │ │ ├── warning_marker.xcf │ │ └── warning_marker_f2.png │ ├── high_48x96 │ └── cursor │ │ ├── cursor_denied.png │ │ ├── cursor_denied.xcf │ │ ├── cursor_destroy.png │ │ ├── cursor_destroy.xcf │ │ ├── cursor_neutral.png │ │ ├── cursor_neutral.xcf │ │ ├── cursor_ok.png │ │ └── cursor_ok.xcf │ ├── small_24x24 │ └── card_marker │ │ ├── card_marker.png │ │ └── card_marker.xcf │ ├── template_multitile.png │ ├── template_multitile_7x7.png │ ├── template_multitile_7x7.xcf │ ├── tileset.json │ ├── tiny_16x16 │ ├── hauler │ │ ├── hauler.json │ │ ├── hauler.png │ │ ├── hauler.xcf │ │ ├── hauler_farm.json │ │ ├── hauler_farm.png │ │ ├── hauler_farm.xcf │ │ ├── hauler_fisherman.json │ │ ├── hauler_fisherman.png │ │ ├── hauler_fisherman.xcf │ │ ├── hauler_lumberjack.json │ │ ├── hauler_lumberjack.png │ │ ├── hauler_lumberjack.xcf │ │ ├── hauler_mason.json │ │ ├── hauler_mason.png │ │ ├── hauler_mason.xcf │ │ └── hauler_shepherd.json │ └── ui_panel │ │ ├── ui_panel.png │ │ ├── ui_panel.xcf │ │ ├── ui_panel_hover.png │ │ ├── ui_panel_hover.xcf │ │ ├── ui_panel_pressed.png │ │ └── ui_panel_pressed.xcf │ └── tiny_8x8 │ └── indicators │ ├── indicator_population.png │ ├── indicator_population.xcf │ ├── indicator_population_inactive.png │ ├── indicator_production.png │ ├── indicator_production.xcf │ ├── indicator_production_inactive.png │ ├── indicator_storage.png │ ├── indicator_storage.xcf │ └── indicator_storage_inactive.png ├── cmd ├── compose │ └── main.go ├── slice │ └── main.go ├── stats │ └── main.go └── util │ ├── data.go │ ├── io.go │ └── walk.go ├── data ├── fonts │ ├── LessRoundBox.ttf │ └── justabit.ttf ├── gfx │ └── paper │ │ ├── buttons_52x52.json │ │ ├── buttons_52x52.png │ │ ├── flat_48x24.json │ │ ├── flat_48x24.png │ │ ├── full_48x48.json │ │ ├── full_48x48.png │ │ ├── half_48x36.json │ │ ├── half_48x36.png │ │ ├── high_48x96.json │ │ ├── high_48x96.png │ │ ├── small_24x24.json │ │ ├── small_24x24.png │ │ ├── tileset.json │ │ ├── tiny_16x16.json │ │ ├── tiny_16x16.png │ │ ├── tiny_8x8.json │ │ └── tiny_8x8.png ├── json │ ├── achievements.json │ ├── resources.json │ ├── rules.json │ └── terrain.json └── maps │ ├── Coastline.json │ ├── Desert Valley.json │ ├── Great Plains.json │ ├── River Delta.json │ ├── River.json │ ├── Rolling Hills.json │ └── Swamp Forest.json ├── docs ├── SCENARIOS.md ├── TILESETS.md ├── TUTORIAL.md └── html │ ├── iframe.css │ ├── iframe.html │ ├── index.html │ ├── style.css │ └── wasm_exec.js ├── embed.go ├── game ├── comp │ └── components.go ├── game.go ├── maps │ └── map.go ├── math │ └── math.go ├── menu │ ├── draw_ui.go │ ├── ui.go │ └── update_ui.go ├── nav │ └── astar.go ├── render │ ├── card_animation.go │ ├── center_view.go │ ├── hauler_paths.go │ ├── markers.go │ ├── terrain.go │ └── ui.go ├── res │ ├── achievements │ │ └── achievements.go │ ├── editor.go │ ├── factory.go │ ├── fonts.go │ ├── game_speed.go │ ├── grid.go │ ├── image.go │ ├── mouse.go │ ├── production.go │ ├── random_terrains.go │ ├── rules.go │ ├── save_event.go │ ├── save_time.go │ ├── selection.go │ ├── sprites.go │ ├── stock.go │ ├── terrain.go │ ├── ui.go │ ├── update.go │ ├── view.go │ └── world_bounds.go ├── resource │ └── resources.go ├── run.go ├── run_nowasm.go ├── run_wasm.go ├── save │ ├── load.go │ ├── load_nowasm.go │ ├── load_wasm.go │ ├── save.go │ ├── save_nowasm.go │ ├── save_wasm.go │ └── types.go ├── sprites │ └── sprites.go ├── sys │ ├── achievements.go │ ├── assign_haulers.go │ ├── build.go │ ├── cheats.go │ ├── do_consumption.go │ ├── do_production.go │ ├── game_controls.go │ ├── haul.go │ ├── init_terrain.go │ ├── init_terrain_loaded.go │ ├── init_terrain_map.go │ ├── init_ui.go │ ├── pan_and_zoom.go │ ├── remove_markers.go │ ├── save_game.go │ ├── tick.go │ ├── update_population.go │ ├── update_production.go │ ├── update_stats.go │ └── update_ui.go ├── terr │ ├── directions.go │ └── terrain.go └── util │ ├── format.go │ ├── pool.go │ └── rect.go ├── go.mod ├── go.sum └── main.go /.github/tiny-world.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | Tiny World 7 | CFBundleIdentifier 8 | com.github.mlange42.tiny-world 9 | CFBundleVersion 10 | 1.0.0 11 | CFBundlePackageType 12 | APPL 13 | CFBundleIconFile 14 | tiny-world.icns 15 | CFBundleExecutable 16 | tiny-world 17 | 18 | -------------------------------------------------------------------------------- /.github/tiny-world.app/Contents/Resources/tiny-world.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/.github/tiny-world.app/Contents/Resources/tiny-world.icns -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | permissions: 12 | contents: write 13 | 14 | env: 15 | GOOS: js 16 | GOARCH: wasm 17 | 18 | jobs: 19 | 20 | build: 21 | name: GitHub Pages 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v3 25 | - name: Setup Go 26 | uses: actions/setup-go@v3 27 | with: 28 | go-version: '1.21.x' 29 | - name: Install dependencies 30 | run: go get ./... 31 | 32 | - name: Build WebAssembly 33 | run: | 34 | go build -ldflags="-s -w" -tags tiny -o docs/html/main.wasm . 35 | 36 | - name: Deploy to GitHub Pages 37 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} 38 | uses: crazy-max/ghaction-github-pages@v4 39 | with: 40 | target_branch: gh-pages 41 | build_dir: docs/html 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | -------------------------------------------------------------------------------- /.github/workflows/tests-wasm.yml: -------------------------------------------------------------------------------- 1 | name: Tests (WASM) 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | env: 12 | GOOS: js 13 | GOARCH: wasm 14 | 15 | jobs: 16 | 17 | build: 18 | name: Build 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Setup Go 23 | uses: actions/setup-go@v3 24 | with: 25 | go-version: '1.21.x' 26 | - name: Install dependencies 27 | run: go get ./... 28 | - name: Build WebAssembly 29 | run: | 30 | go build -o test/main.wasm . 31 | 32 | test: 33 | name: Run tests 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Set up Go 37 | uses: actions/setup-go@v2 38 | with: 39 | go-version: '1.21.x' 40 | - name: Check out code 41 | uses: actions/checkout@v2 42 | - name: Install dependencies 43 | run: | 44 | go get ./... 45 | - name: Run Unit tests 46 | run: | 47 | go test -v -covermode atomic -coverprofile="coverage.out" ./... 48 | go tool cover -func="coverage.out" 49 | 50 | lint: 51 | name: Run linters 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v3 55 | - name: Setup Go 56 | uses: actions/setup-go@v3 57 | with: 58 | go-version: '1.21.x' 59 | - name: Install dependencies 60 | run: | 61 | go get ./... 62 | - name: Check format 63 | run: | 64 | if gofmt -e -l . >&1 | grep '^'; then 65 | exit 1 66 | fi 67 | - name: Lint with vet 68 | run: go vet ./... 69 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | 13 | build: 14 | name: Build 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Setup Go 19 | uses: actions/setup-go@v3 20 | with: 21 | go-version: '1.21.x' 22 | - name: Install dependencies 23 | run: | 24 | sudo apt-get update -y 25 | sudo apt-get install -y libgl1-mesa-dev xorg-dev 26 | go get ./... 27 | - name: Build WebAssembly 28 | run: | 29 | go build -o test/main . 30 | 31 | test: 32 | name: Run tests 33 | runs-on: ubuntu-latest 34 | steps: 35 | - name: Set up Go 36 | uses: actions/setup-go@v2 37 | with: 38 | go-version: '1.21.x' 39 | - name: Check out code 40 | uses: actions/checkout@v2 41 | - name: Install dependencies 42 | run: | 43 | sudo apt-get update -y 44 | sudo apt-get install -y libgl1-mesa-dev xorg-dev 45 | go get ./... 46 | - name: Run Unit tests 47 | run: | 48 | go test -v -covermode atomic -coverprofile="coverage.out" ./... 49 | go tool cover -func="coverage.out" 50 | 51 | lint: 52 | name: Run linters 53 | runs-on: ubuntu-latest 54 | steps: 55 | - uses: actions/checkout@v3 56 | - name: Setup Go 57 | uses: actions/setup-go@v3 58 | with: 59 | go-version: '1.21.x' 60 | - name: Install dependencies 61 | run: | 62 | sudo apt-get update -y 63 | sudo apt-get install -y libgl1-mesa-dev xorg-dev 64 | go get ./... 65 | go install honnef.co/go/tools/cmd/staticcheck@latest 66 | go install github.com/gordonklaus/ineffassign@latest 67 | - name: Check format 68 | run: | 69 | if gofmt -e -l . >&1 | grep '^'; then 70 | exit 1 71 | fi 72 | - name: Lint with vet 73 | run: go vet ./... 74 | #- name: Lint with staticcheck 75 | # run: staticcheck ./... 76 | - name: Lint with ineffassign 77 | run: ineffassign ./... 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.svg 3 | *.wasm 4 | /save/ 5 | /maps/ 6 | /user/ 7 | 8 | # macOS binary 9 | ./tiny-world 10 | 11 | .idea -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | ## Installation Guide 2 | 3 | ### Precompiled binaries 4 | 5 | You can download precompiled binaries for Linux, Windows and macOS from the [Releases](https://github.com/mlange-42/tiny-world/releases). 6 | 7 | #### macOS version 8 | For the macOS version, please right-click the app and select "Open" to bypass the security warning, as the binary is not signed. 9 | 10 | In case you get the message `“tiny-world.app” is damaged and can’t be opened. You should move it to the Bin.`, please use the following command from the terminal: 11 | ```shell 12 | xattr -c tiny-world.app 13 | ``` 14 | This will remove the quarantine attribute from the app. You can then open it as usual. 15 | 16 | ### Build from source 17 | 18 | Clone the repository and build or run the game with [Go](https://go.dev): 19 | 20 | ```shell 21 | git clone https://github.com/mlange-42/tiny-world.git 22 | cd tiny-world 23 | go run . 24 | ``` 25 | 26 | For building on Unix systems, `libgl1-mesa-dev` and `xorg-dev` are required. 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Martin Lange 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tiny World 2 | 3 | A tiny, slow-paced world and colony building game. 4 | 5 | Made with [Ebitengine](https://github.com/hajimehoshi/ebiten) and the [Arche](https://github.com/mlange-42/arche) Entity Component System. 6 | 7 |
8 | Tiny World screenshot 9 |
10 | 11 | ## Usage 12 | 13 | ### Play in browser 14 | 15 | You can play Tiny World [on itch.io](https://mlange-42.itch.io/tiny-world), 16 | or the development version [here](https://mlange-42.github.io/tiny-world/). 17 | 18 | ### Run locally 19 | 20 | Please check the [installation guide here](INSTALL.md). 21 | 22 | ## Playing 23 | 24 | In the toolbar on the right, the top items are **buildings** that can be bought by the player for resources. 25 | The **natural features** in the lower part appear randomly and are replenished when placed by the player. 26 | 27 | * Pan: Arrows, WASD or middle mouse button 28 | * Zoom: +/- or mouse wheel 29 | * Pause/resume: Space 30 | * Game speed: [/] (square brackets) 31 | * Toggle fullscreen: F11 32 | 33 | All UI controls have tooltips. Read them carefully! 34 | -------------------------------------------------------------------------------- /artwork/sprites/paper/buttons_52x52/button/button.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "button", 4 | "file": ["button"] 5 | }, 6 | { 7 | "id": "button_hover", 8 | "file": ["button_pressed"] 9 | }, 10 | { 11 | "id": "button_pressed", 12 | "file": ["button_pressed"] 13 | }, 14 | { 15 | "id": "button_disabled", 16 | "file": ["button_disabled"] 17 | } 18 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/buttons_52x52/button/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/buttons_52x52/button/button.png -------------------------------------------------------------------------------- /artwork/sprites/paper/buttons_52x52/button/button.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/buttons_52x52/button/button.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/buttons_52x52/button/button_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/buttons_52x52/button/button_disabled.png -------------------------------------------------------------------------------- /artwork/sprites/paper/buttons_52x52/button/button_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/buttons_52x52/button/button_pressed.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "border_inner", 4 | "file": [ 5 | "border_inner" 6 | ], 7 | "multitile": [ 8 | [ 9 | "border_inner" 10 | ], 11 | [ 12 | "border_inner_01" 13 | ], 14 | [ 15 | "border_inner_02" 16 | ], 17 | [ 18 | "border_inner_03" 19 | ], 20 | [ 21 | "border_inner_04" 22 | ], 23 | [ 24 | "border_inner_05" 25 | ], 26 | [ 27 | "border_inner_06" 28 | ], 29 | [ 30 | "border_inner_07" 31 | ], 32 | [ 33 | "border_inner_08" 34 | ], 35 | [ 36 | "border_inner_09" 37 | ], 38 | [ 39 | "border_inner_10" 40 | ], 41 | [ 42 | "border_inner_11" 43 | ], 44 | [ 45 | "border_inner_12" 46 | ], 47 | [ 48 | "border_inner_13" 49 | ], 50 | [ 51 | "border_inner_14" 52 | ], 53 | [ 54 | "border_inner_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_inner_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_inner_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_multitile/border_inner.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "border_inner", 3 | "file": "border_inner", 4 | "height": 0 5 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_multitile/border_inner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_multitile/border_inner.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_multitile/border_inner.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_multitile/border_inner.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_multitile/border_outer.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "border_outer", 3 | "file": "border_outer", 4 | "height": 0 5 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_multitile/border_outer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_multitile/border_outer.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_multitile/border_outer.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_multitile/border_outer.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "border_outer", 4 | "file": [ 5 | "border_outer" 6 | ], 7 | "multitile": [ 8 | [ 9 | "border_outer" 10 | ], 11 | [ 12 | "border_outer_01" 13 | ], 14 | [ 15 | "border_outer_02" 16 | ], 17 | [ 18 | "border_outer_03" 19 | ], 20 | [ 21 | "border_outer_04" 22 | ], 23 | [ 24 | "border_outer_05" 25 | ], 26 | [ 27 | "border_outer_06" 28 | ], 29 | [ 30 | "border_outer_07" 31 | ], 32 | [ 33 | "border_outer_08" 34 | ], 35 | [ 36 | "border_outer_09" 37 | ], 38 | [ 39 | "border_outer_10" 40 | ], 41 | [ 42 | "border_outer_11" 43 | ], 44 | [ 45 | "border_outer_12" 46 | ], 47 | [ 48 | "border_outer_13" 49 | ], 50 | [ 51 | "border_outer_14" 52 | ], 53 | [ 54 | "border_outer_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/border/border_outer_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/border/border_outer_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "bridge", 4 | "file": [ 5 | "bridge" 6 | ], 7 | "multitile": [ 8 | [ 9 | "bridge" 10 | ], 11 | [ 12 | "bridge_01" 13 | ], 14 | [ 15 | "bridge_02" 16 | ], 17 | [ 18 | "bridge_03" 19 | ], 20 | [ 21 | "bridge_04" 22 | ], 23 | [ 24 | "bridge_05" 25 | ], 26 | [ 27 | "bridge_06" 28 | ], 29 | [ 30 | "bridge_07" 31 | ], 32 | [ 33 | "bridge_08" 34 | ], 35 | [ 36 | "bridge_09" 37 | ], 38 | [ 39 | "bridge_10" 40 | ], 41 | [ 42 | "bridge_11" 43 | ], 44 | [ 45 | "bridge_12" 46 | ], 47 | [ 48 | "bridge_13" 49 | ], 50 | [ 51 | "bridge_14" 52 | ], 53 | [ 54 | "bridge_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_multitile/bridge.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "bridge", 3 | "file": "bridge" 4 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_multitile/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_multitile/bridge.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/bridge/bridge_multitile/bridge.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/bridge/bridge_multitile/bridge.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "building_base", 4 | "file": [ 5 | "building_base" 6 | ], 7 | "multitile": [ 8 | [ 9 | "building_base" 10 | ], 11 | [ 12 | "building_base_01" 13 | ], 14 | [ 15 | "building_base_02" 16 | ], 17 | [ 18 | "building_base_03" 19 | ], 20 | [ 21 | "building_base_04" 22 | ], 23 | [ 24 | "building_base_05" 25 | ], 26 | [ 27 | "building_base_06" 28 | ], 29 | [ 30 | "building_base_07" 31 | ], 32 | [ 33 | "building_base_08" 34 | ], 35 | [ 36 | "building_base_09" 37 | ], 38 | [ 39 | "building_base_10" 40 | ], 41 | [ 42 | "building_base_11" 43 | ], 44 | [ 45 | "building_base_12" 46 | ], 47 | [ 48 | "building_base_13" 49 | ], 50 | [ 51 | "building_base_14" 52 | ], 53 | [ 54 | "building_base_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_multitile/building_base.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "building_base", 3 | "file": "building_base" 4 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_multitile/building_base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_multitile/building_base.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/building_base/building_base_multitile/building_base.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/building_base/building_base_multitile/building_base.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "desert", 4 | "file": [ 5 | "desert" 6 | ], 7 | "multitile": [ 8 | [ 9 | "desert" 10 | ], 11 | [ 12 | "desert_01" 13 | ], 14 | [ 15 | "desert_02" 16 | ], 17 | [ 18 | "desert_03" 19 | ], 20 | [ 21 | "desert_04" 22 | ], 23 | [ 24 | "desert_05" 25 | ], 26 | [ 27 | "desert_06" 28 | ], 29 | [ 30 | "desert_07" 31 | ], 32 | [ 33 | "desert_08" 34 | ], 35 | [ 36 | "desert_09" 37 | ], 38 | [ 39 | "desert_10" 40 | ], 41 | [ 42 | "desert_11" 43 | ], 44 | [ 45 | "desert_12" 46 | ], 47 | [ 48 | "desert_13" 49 | ], 50 | [ 51 | "desert_14" 52 | ], 53 | [ 54 | "desert_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_multitile/desert.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "desert", 3 | "file": "desert", 4 | "height": 0 5 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_multitile/desert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_multitile/desert.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/desert/desert_multitile/desert.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/desert/desert_multitile/desert.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/food/food.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/food/food.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/food/food.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/food/food.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "hills", 4 | "file": ["hills", "hills_v2", "hills_v3", "hills_v4", "hills_v5", "hills_v6"] 5 | } 6 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/hills/hills.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/hills/hills.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/hills/hills_v2.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills_v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/hills/hills_v3.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills_v4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/hills/hills_v4.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills_v5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/hills/hills_v5.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/hills/hills_v6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/hills/hills_v6.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "path", 4 | "file": [ 5 | "path" 6 | ], 7 | "multitile": [ 8 | [ 9 | "path" 10 | ], 11 | [ 12 | "path_01" 13 | ], 14 | [ 15 | "path_02" 16 | ], 17 | [ 18 | "path_03" 19 | ], 20 | [ 21 | "path_04" 22 | ], 23 | [ 24 | "path_05" 25 | ], 26 | [ 27 | "path_06" 28 | ], 29 | [ 30 | "path_07" 31 | ], 32 | [ 33 | "path_08" 34 | ], 35 | [ 36 | "path_09" 37 | ], 38 | [ 39 | "path_10" 40 | ], 41 | [ 42 | "path_11" 43 | ], 44 | [ 45 | "path_12" 46 | ], 47 | [ 48 | "path_13" 49 | ], 50 | [ 51 | "path_14" 52 | ], 53 | [ 54 | "path_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_multitile/path.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "path", 3 | "file": "path" 4 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_multitile/path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_multitile/path.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/path/path_multitile/path.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/path/path_multitile/path.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/stones/stones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/stones/stones.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/stones/stones.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/stones/stones.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "water", 4 | "file": [ 5 | "water" 6 | ], 7 | "multitile": [ 8 | [ 9 | "water" 10 | ], 11 | [ 12 | "water_01" 13 | ], 14 | [ 15 | "water_02" 16 | ], 17 | [ 18 | "water_03" 19 | ], 20 | [ 21 | "water_04" 22 | ], 23 | [ 24 | "water_05" 25 | ], 26 | [ 27 | "water_06" 28 | ], 29 | [ 30 | "water_07" 31 | ], 32 | [ 33 | "water_08" 34 | ], 35 | [ 36 | "water_09" 37 | ], 38 | [ 39 | "water_10" 40 | ], 41 | [ 42 | "water_11" 43 | ], 44 | [ 45 | "water_12" 46 | ], 47 | [ 48 | "water_13" 49 | ], 50 | [ 51 | "water_14" 52 | ], 53 | [ 54 | "water_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_multitile/water.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "water", 3 | "file": "water", 4 | "height": 0 5 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_multitile/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_multitile/water.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/water/water_multitile/water.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/water/water_multitile/water.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/wood/wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/wood/wood.png -------------------------------------------------------------------------------- /artwork/sprites/paper/flat_48x24/wood/wood.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/flat_48x24/wood/wood.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/buildable/buildable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/buildable/buildable.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/buildable/buildable.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/buildable/buildable.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/bulldoze/bulldoze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/bulldoze/bulldoze.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/bulldoze/bulldoze.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/bulldoze/bulldoze.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/castle/castle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/castle/castle.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/castle/castle.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/castle/castle.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/castle/tower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/castle/tower.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/castle/tower.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/castle/tower.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/castle/tower_large.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/castle/tower_large.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/church/church.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/church/church.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/church/church.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/church/church.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/farm/farm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/farm/farm.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/farm/farm.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/farm/farm.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/fisherman/fisherman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/fisherman/fisherman.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/fisherman/fisherman.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/fisherman/fisherman.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/lumberjack/lumberjack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/lumberjack/lumberjack.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/lumberjack/lumberjack.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/lumberjack/lumberjack.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/mason/mason.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/mason/mason.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/mason/mason.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/mason/mason.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/monastery/monastery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/monastery/monastery.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/monastery/monastery.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/monastery/monastery.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "plains", 4 | "file": [ 5 | "plains" 6 | ], 7 | "height": 24, 8 | "multitile": [ 9 | [ 10 | "plains" 11 | ], 12 | [ 13 | "plains_01" 14 | ], 15 | [ 16 | "plains_02" 17 | ], 18 | [ 19 | "plains_03" 20 | ], 21 | [ 22 | "plains_04" 23 | ], 24 | [ 25 | "plains_05" 26 | ], 27 | [ 28 | "plains_06" 29 | ], 30 | [ 31 | "plains_07" 32 | ], 33 | [ 34 | "plains_08" 35 | ], 36 | [ 37 | "plains_09" 38 | ], 39 | [ 40 | "plains_10" 41 | ], 42 | [ 43 | "plains_11" 44 | ], 45 | [ 46 | "plains_12" 47 | ], 48 | [ 49 | "plains_13" 50 | ], 51 | [ 52 | "plains_14" 53 | ], 54 | [ 55 | "plains_15", 56 | "plains_15_r1", 57 | "plains_15_r2", 58 | "plains_15_r3", 59 | "plains_15_r4" 60 | ] 61 | ] 62 | } 63 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_15.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_15.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_15_r1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_15_r1.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_15_r2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_15_r2.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_15_r3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_15_r3.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_15_r4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_15_r4.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "plains", 3 | "file": "plains", 4 | "base": "plains_base", 5 | "height": 24 6 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains_base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains_base.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains_base.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/plains/plains_multitile_off/plains_base.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/rock/rock.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "rock", 3 | "file": ["rock_01", "rock_02"] 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/rock/rock_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/rock/rock_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/rock/rock_01.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/rock/rock_01.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/rock/rock_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/rock/rock_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/rock/rock_02.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/rock/rock_02.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/shepherd/shepherd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/shepherd/shepherd.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/shepherd/shepherd.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/shepherd/shepherd.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "tree", 3 | "file": [ 4 | "tree_c_01", "tree_c_02", 5 | "tree_d_01", "tree_d_02" 6 | ] 7 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_c_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_c_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_c_01.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_c_01.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_c_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_c_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_c_02.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_c_02.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_d_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_d_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_d_01.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_d_01.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_d_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_d_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/tree/tree_d_02.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/tree/tree_d_02.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/unknown/unknown.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "unknown", 3 | "height": 25 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/unknown/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/unknown/unknown.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/unknown/unknown.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/unknown/unknown.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/warehouse/warehouse.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "warehouse", 4 | "file": ["warehouse"], 5 | "multitile": [ 6 | ["warehouse"], 7 | ["warehouse"], 8 | ["warehouse"], 9 | ["warehouse"], 10 | ["warehouse_S"], 11 | ["warehouse_S"], 12 | ["warehouse"], 13 | ["warehouse"], 14 | ["warehouse"], 15 | ["warehouse"], 16 | ["warehouse"], 17 | ["warehouse"], 18 | ["warehouse_S"], 19 | ["warehouse_S"], 20 | ["warehouse"], 21 | ["warehouse"] 22 | ] 23 | } 24 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/warehouse/warehouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/warehouse/warehouse.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/warehouse/warehouse.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/warehouse/warehouse.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/warehouse/warehouse_S.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/warehouse/warehouse_S.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/watermill/watermill.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "watermill", 4 | "file": ["watermill_S"], 5 | "multitile": [ 6 | ["watermill_S"], 7 | ["watermill_N"], 8 | ["watermill_E"], 9 | ["watermill_E"], 10 | ["watermill_S"], 11 | ["watermill_S"], 12 | ["watermill_S"], 13 | ["watermill_S"], 14 | ["watermill_W"], 15 | ["watermill_N"], 16 | ["watermill_E"], 17 | ["watermill_E"], 18 | ["watermill_S"], 19 | ["watermill_S"], 20 | ["watermill_S"], 21 | ["watermill_S"] 22 | ] 23 | } 24 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/watermill/watermill.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/watermill/watermill.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/watermill/watermill_E.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/watermill/watermill_E.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/watermill/watermill_N.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/watermill/watermill_N.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/watermill/watermill_S.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/watermill/watermill_S.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/watermill/watermill_W.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/watermill/watermill_W.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/windmill/windmill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/windmill/windmill.png -------------------------------------------------------------------------------- /artwork/sprites/paper/full_48x48/windmill/windmill.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/full_48x48/windmill/windmill.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "fence", 4 | "file": [ 5 | "fence" 6 | ], 7 | "multitile": [ 8 | [ 9 | "fence" 10 | ], 11 | [ 12 | "fence_01" 13 | ], 14 | [ 15 | "fence_02" 16 | ], 17 | [ 18 | "fence_03" 19 | ], 20 | [ 21 | "fence_04" 22 | ], 23 | [ 24 | "fence_05" 25 | ], 26 | [ 27 | "fence_06" 28 | ], 29 | [ 30 | "fence_07" 31 | ], 32 | [ 33 | "fence_08" 34 | ], 35 | [ 36 | "fence_09" 37 | ], 38 | [ 39 | "fence_10" 40 | ], 41 | [ 42 | "fence_11" 43 | ], 44 | [ 45 | "fence_12" 46 | ], 47 | [ 48 | "fence_13" 49 | ], 50 | [ 51 | "fence_14" 52 | ], 53 | [ 54 | "fence_15" 55 | ] 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_01.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_02.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_03.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_04.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_05.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_06.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_07.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_08.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_09.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_10.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_11.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_12.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_13.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_14.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/fence/fence_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/fence/fence_15.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/field/field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/field/field.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/field/field.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/field/field.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/pasture/pasture.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "pasture", 3 | "file": ["pasture", "pasture_v2", "pasture_v3"] 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/pasture/pasture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/pasture/pasture.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/pasture/pasture.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/pasture/pasture.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/pasture/pasture_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/pasture/pasture_v2.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/pasture/pasture_v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/pasture/pasture_v3.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/warning_marker/warning_marker.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "warning_marker", 4 | "file": [ 5 | "warning_marker", "warning_marker", "warning_marker", "warning_marker", 6 | "warning_marker", "warning_marker_f2" 7 | ], 8 | "animation_frames": 6, 9 | "animation_speed": 15, 10 | "y_offset": 36 11 | } 12 | ] -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/warning_marker/warning_marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/warning_marker/warning_marker.png -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/warning_marker/warning_marker.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/warning_marker/warning_marker.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/half_48x36/warning_marker/warning_marker_f2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/half_48x36/warning_marker/warning_marker_f2.png -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_denied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_denied.png -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_denied.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_denied.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_destroy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_destroy.png -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_destroy.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_destroy.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_neutral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_neutral.png -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_neutral.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_neutral.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_ok.png -------------------------------------------------------------------------------- /artwork/sprites/paper/high_48x96/cursor/cursor_ok.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/high_48x96/cursor/cursor_ok.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/small_24x24/card_marker/card_marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/small_24x24/card_marker/card_marker.png -------------------------------------------------------------------------------- /artwork/sprites/paper/small_24x24/card_marker/card_marker.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/small_24x24/card_marker/card_marker.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/template_multitile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/template_multitile.png -------------------------------------------------------------------------------- /artwork/sprites/paper/template_multitile_7x7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/template_multitile_7x7.png -------------------------------------------------------------------------------- /artwork/sprites/paper/template_multitile_7x7.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/template_multitile_7x7.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tileset.json: -------------------------------------------------------------------------------- 1 | { 2 | "tile_width": 48, 3 | "tile_height": 24, 4 | "background_color": {"R": 189, "G": 181, "B": 161, "A": 255}, 5 | "text_color": {"R": 70, "G": 65, "B": 50, "A": 255}, 6 | "text_highlight_color": {"R": 188, "G": 10, "B": 10, "A": 255} 7 | } -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "hauler", 3 | "y_offset": 10 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_farm.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "hauler_farm", 3 | "y_offset": 10 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_farm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_farm.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_farm.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_farm.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_fisherman.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "hauler_fisherman", 3 | "y_offset": 10 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_fisherman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_fisherman.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_fisherman.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_fisherman.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_lumberjack.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "hauler_lumberjack", 3 | "y_offset": 10 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_lumberjack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_lumberjack.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_lumberjack.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_lumberjack.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_mason.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "hauler_mason", 3 | "y_offset": 10 4 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_mason.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_mason.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_mason.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/hauler/hauler_mason.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/hauler/hauler_shepherd.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": "hauler_shepherd", 3 | "file": ["hauler_farm"], 4 | "y_offset": 10 5 | }] -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_hover.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_hover.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_hover.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_pressed.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_pressed.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_16x16/ui_panel/ui_panel_pressed.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_population.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_population.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_population.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_population.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_population_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_population_inactive.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_production.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_production.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_production.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_production.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_production_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_production_inactive.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_storage.png -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_storage.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_storage.xcf -------------------------------------------------------------------------------- /artwork/sprites/paper/tiny_8x8/indicators/indicator_storage_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/artwork/sprites/paper/tiny_8x8/indicators/indicator_storage_inactive.png -------------------------------------------------------------------------------- /cmd/stats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math" 7 | "os" 8 | "strings" 9 | 10 | "github.com/mlange-42/tiny-world/game/resource" 11 | "github.com/mlange-42/tiny-world/game/save" 12 | "github.com/mlange-42/tiny-world/game/terr" 13 | ) 14 | 15 | func main() { 16 | if len(os.Args) != 2 { 17 | log.Fatal("Please specify a map file!") 18 | } 19 | file := os.Args[1] 20 | if !strings.HasSuffix(file, ".json") { 21 | file += ".json" 22 | } 23 | mapStr, err := os.ReadFile(file) 24 | if err != nil { 25 | log.Fatalf("Error reading map '%s': %s", file, err.Error()) 26 | } 27 | 28 | mapData, err := save.ParseMap(string(mapStr)) 29 | if err != nil { 30 | log.Fatalf("Error parsing map '%s': %s", file, err.Error()) 31 | } 32 | 33 | resource.Prepare(os.DirFS("."), "data/json/resources.json") 34 | terr.Prepare(os.DirFS("."), "data/json/terrain.json") 35 | 36 | frequencies := map[terr.Terrain]int{} 37 | total := 0 38 | 39 | for y := 0; y < len(mapData.Data); y++ { 40 | line := mapData.Data[y] 41 | for x := 0; x < len(line); x++ { 42 | rn := line[x] 43 | ter, ok := terr.SymbolToTerrain[rn] 44 | if !ok { 45 | panic(fmt.Sprintf("unknown map symbol '%s'", string(rn))) 46 | } 47 | tBits := terr.Properties[ter.Terrain].TerrainBits 48 | luBits := terr.Properties[ter.LandUse].TerrainBits 49 | if ter.Terrain != terr.Air && tBits.Contains(terr.CanBuild) && !tBits.Contains(terr.CanBuy) { 50 | if cnt, ok := frequencies[ter.Terrain]; ok { 51 | frequencies[ter.Terrain] = cnt + 1 52 | } else { 53 | frequencies[ter.Terrain] = 1 54 | } 55 | total++ 56 | } 57 | if ter.LandUse != terr.Air && luBits.Contains(terr.CanBuild) && !luBits.Contains(terr.CanBuy) { 58 | if cnt, ok := frequencies[ter.LandUse]; ok { 59 | frequencies[ter.LandUse] = cnt + 1 60 | } else { 61 | frequencies[ter.LandUse] = 1 62 | } 63 | total++ 64 | } 65 | } 66 | } 67 | 68 | minCount := math.MaxInt 69 | for _, cnt := range frequencies { 70 | if cnt < minCount { 71 | minCount = cnt 72 | } 73 | } 74 | 75 | for t, cnt := range frequencies { 76 | fmt.Printf("%10s (%s): %4d (%5.1f%%) %5.1fx\n", 77 | terr.Properties[t].Name, string(terr.Properties[t].Symbols[0]), 78 | cnt, 79 | float64(cnt*100)/float64(total), float64(cnt)/float64(minCount)) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /cmd/util/data.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "image/color" 4 | 5 | type TileSet struct { 6 | TileWidth int `json:"tile_width"` 7 | TileHeight int `json:"tile_height"` 8 | BackgroundColor color.RGBA `json:"background_color"` 9 | TextColor color.RGBA `json:"text_color"` 10 | TextHighlightColor color.RGBA `json:"text_highlight_color"` 11 | } 12 | 13 | type RawSprite struct { 14 | Id string `json:"id"` 15 | File []string `json:"file"` 16 | Height int `json:"height,omitempty"` 17 | YOffset int `json:"y_offset,omitempty"` 18 | AnimFrames int `json:"animation_frames,omitempty"` 19 | AnimSpeed int `json:"animation_speed,omitempty"` 20 | Multitile [][]string `json:"multitile,omitempty"` 21 | } 22 | 23 | type Sprite struct { 24 | Id string `json:"id"` 25 | Index []int `json:"index"` 26 | Height int `json:"height,omitempty"` 27 | YOffset int `json:"y_offset,omitempty"` 28 | AnimFrames int `json:"animation_frames,omitempty"` 29 | AnimSpeed int `json:"animation_speed,omitempty"` 30 | Multitile [][]int `json:"multitile,omitempty"` 31 | } 32 | 33 | func (s *Sprite) IsMultitile() bool { 34 | return len(s.Multitile) > 0 35 | } 36 | 37 | func (s *Sprite) IsAnimated() bool { 38 | return s.AnimFrames > 1 39 | } 40 | 41 | type RawSpriteSheet struct { 42 | Directory string 43 | Width int 44 | Height int 45 | } 46 | 47 | type SpriteSheet struct { 48 | SpriteWidth int `json:"sprite_width"` 49 | SpriteHeight int `json:"sprite_height"` 50 | Sprites []Sprite `json:"sprites"` 51 | TotalSprites int `json:"total_sprites"` 52 | } 53 | 54 | type Directory struct { 55 | Dir string 56 | HasJson bool 57 | Files []File 58 | Directories []Directory 59 | } 60 | 61 | type File struct { 62 | Name string 63 | IsJson bool 64 | } 65 | -------------------------------------------------------------------------------- /cmd/util/io.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/json" 5 | "image" 6 | "image/png" 7 | "io/fs" 8 | "os" 9 | ) 10 | 11 | func FromJson(file string, obj any) error { 12 | ff, err := os.Open(file) 13 | if err != nil { 14 | return err 15 | } 16 | decoder := json.NewDecoder(ff) 17 | decoder.DisallowUnknownFields() 18 | return decoder.Decode(obj) 19 | } 20 | 21 | func ToJson(file string, obj any) error { 22 | js, err := json.MarshalIndent(obj, "", " ") 23 | if err != nil { 24 | return err 25 | } 26 | return os.WriteFile(file, js, 0666) 27 | } 28 | 29 | func FromJsonFs(f fs.FS, file string, obj any) error { 30 | ff, err := f.Open(file) 31 | if err != nil { 32 | return err 33 | } 34 | decoder := json.NewDecoder(ff) 35 | decoder.DisallowUnknownFields() 36 | return decoder.Decode(obj) 37 | } 38 | 39 | func ReadImage(p string) (image.Image, error) { 40 | f, err := os.Open(p) 41 | if err != nil { 42 | return nil, err 43 | } 44 | defer f.Close() 45 | baseSprite, _, err := image.Decode(f) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | return baseSprite, nil 51 | } 52 | 53 | func WriteImage(file string, img image.Image) error { 54 | f, err := os.Create(file) 55 | if err != nil { 56 | return err 57 | } 58 | defer f.Close() 59 | 60 | return png.Encode(f, img) 61 | } 62 | -------------------------------------------------------------------------------- /data/fonts/LessRoundBox.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/fonts/LessRoundBox.ttf -------------------------------------------------------------------------------- /data/fonts/justabit.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/fonts/justabit.ttf -------------------------------------------------------------------------------- /data/gfx/paper/buttons_52x52.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite_width": 52, 3 | "sprite_height": 52, 4 | "sprites": [ 5 | { 6 | "id": "button", 7 | "index": [ 8 | 0 9 | ] 10 | }, 11 | { 12 | "id": "button_hover", 13 | "index": [ 14 | 1 15 | ] 16 | }, 17 | { 18 | "id": "button_pressed", 19 | "index": [ 20 | 1 21 | ] 22 | }, 23 | { 24 | "id": "button_disabled", 25 | "index": [ 26 | 2 27 | ] 28 | } 29 | ], 30 | "total_sprites": 3 31 | } -------------------------------------------------------------------------------- /data/gfx/paper/buttons_52x52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/buttons_52x52.png -------------------------------------------------------------------------------- /data/gfx/paper/flat_48x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/flat_48x24.png -------------------------------------------------------------------------------- /data/gfx/paper/full_48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/full_48x48.png -------------------------------------------------------------------------------- /data/gfx/paper/half_48x36.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite_width": 48, 3 | "sprite_height": 36, 4 | "sprites": [ 5 | { 6 | "id": "fence", 7 | "index": [ 8 | 0 9 | ], 10 | "multitile": [ 11 | [ 12 | 0 13 | ], 14 | [ 15 | 1 16 | ], 17 | [ 18 | 2 19 | ], 20 | [ 21 | 3 22 | ], 23 | [ 24 | 4 25 | ], 26 | [ 27 | 5 28 | ], 29 | [ 30 | 6 31 | ], 32 | [ 33 | 7 34 | ], 35 | [ 36 | 8 37 | ], 38 | [ 39 | 9 40 | ], 41 | [ 42 | 10 43 | ], 44 | [ 45 | 11 46 | ], 47 | [ 48 | 12 49 | ], 50 | [ 51 | 13 52 | ], 53 | [ 54 | 14 55 | ], 56 | [ 57 | 15 58 | ] 59 | ] 60 | }, 61 | { 62 | "id": "field", 63 | "index": [ 64 | 16 65 | ] 66 | }, 67 | { 68 | "id": "pasture", 69 | "index": [ 70 | 17, 71 | 18, 72 | 19 73 | ] 74 | }, 75 | { 76 | "id": "warning_marker", 77 | "index": [ 78 | 20, 79 | 20, 80 | 20, 81 | 20, 82 | 20, 83 | 21 84 | ], 85 | "y_offset": 36, 86 | "animation_frames": 6, 87 | "animation_speed": 15 88 | } 89 | ], 90 | "total_sprites": 22 91 | } -------------------------------------------------------------------------------- /data/gfx/paper/half_48x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/half_48x36.png -------------------------------------------------------------------------------- /data/gfx/paper/high_48x96.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite_width": 48, 3 | "sprite_height": 96, 4 | "sprites": [ 5 | { 6 | "id": "cursor_denied", 7 | "index": [ 8 | 0 9 | ] 10 | }, 11 | { 12 | "id": "cursor_destroy", 13 | "index": [ 14 | 1 15 | ] 16 | }, 17 | { 18 | "id": "cursor_neutral", 19 | "index": [ 20 | 2 21 | ] 22 | }, 23 | { 24 | "id": "cursor_ok", 25 | "index": [ 26 | 3 27 | ] 28 | } 29 | ], 30 | "total_sprites": 4 31 | } -------------------------------------------------------------------------------- /data/gfx/paper/high_48x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/high_48x96.png -------------------------------------------------------------------------------- /data/gfx/paper/small_24x24.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite_width": 24, 3 | "sprite_height": 24, 4 | "sprites": [ 5 | { 6 | "id": "card_marker", 7 | "index": [ 8 | 0 9 | ] 10 | } 11 | ], 12 | "total_sprites": 1 13 | } -------------------------------------------------------------------------------- /data/gfx/paper/small_24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/small_24x24.png -------------------------------------------------------------------------------- /data/gfx/paper/tileset.json: -------------------------------------------------------------------------------- 1 | { 2 | "tile_width": 48, 3 | "tile_height": 24, 4 | "background_color": { 5 | "R": 189, 6 | "G": 181, 7 | "B": 161, 8 | "A": 255 9 | }, 10 | "text_color": { 11 | "R": 70, 12 | "G": 65, 13 | "B": 50, 14 | "A": 255 15 | }, 16 | "text_highlight_color": { 17 | "R": 188, 18 | "G": 10, 19 | "B": 10, 20 | "A": 255 21 | } 22 | } -------------------------------------------------------------------------------- /data/gfx/paper/tiny_16x16.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite_width": 16, 3 | "sprite_height": 16, 4 | "sprites": [ 5 | { 6 | "id": "hauler", 7 | "index": [ 8 | 0 9 | ], 10 | "y_offset": 10 11 | }, 12 | { 13 | "id": "hauler_farm", 14 | "index": [ 15 | 1 16 | ], 17 | "y_offset": 10 18 | }, 19 | { 20 | "id": "hauler_fisherman", 21 | "index": [ 22 | 2 23 | ], 24 | "y_offset": 10 25 | }, 26 | { 27 | "id": "hauler_lumberjack", 28 | "index": [ 29 | 3 30 | ], 31 | "y_offset": 10 32 | }, 33 | { 34 | "id": "hauler_mason", 35 | "index": [ 36 | 4 37 | ], 38 | "y_offset": 10 39 | }, 40 | { 41 | "id": "hauler_shepherd", 42 | "index": [ 43 | 1 44 | ], 45 | "y_offset": 10 46 | }, 47 | { 48 | "id": "ui_panel", 49 | "index": [ 50 | 5 51 | ] 52 | }, 53 | { 54 | "id": "ui_panel_hover", 55 | "index": [ 56 | 6 57 | ] 58 | }, 59 | { 60 | "id": "ui_panel_pressed", 61 | "index": [ 62 | 7 63 | ] 64 | } 65 | ], 66 | "total_sprites": 8 67 | } -------------------------------------------------------------------------------- /data/gfx/paper/tiny_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/tiny_16x16.png -------------------------------------------------------------------------------- /data/gfx/paper/tiny_8x8.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite_width": 8, 3 | "sprite_height": 8, 4 | "sprites": [ 5 | { 6 | "id": "indicator_population", 7 | "index": [ 8 | 0 9 | ] 10 | }, 11 | { 12 | "id": "indicator_population_inactive", 13 | "index": [ 14 | 1 15 | ] 16 | }, 17 | { 18 | "id": "indicator_production", 19 | "index": [ 20 | 2 21 | ] 22 | }, 23 | { 24 | "id": "indicator_production_inactive", 25 | "index": [ 26 | 3 27 | ] 28 | }, 29 | { 30 | "id": "indicator_storage", 31 | "index": [ 32 | 4 33 | ] 34 | }, 35 | { 36 | "id": "indicator_storage_inactive", 37 | "index": [ 38 | 5 39 | ] 40 | } 41 | ], 42 | "total_sprites": 6 43 | } -------------------------------------------------------------------------------- /data/gfx/paper/tiny_8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mlange-42/tiny-world/7e0b14d661d87eda29526ccf970bd9f78e0207f3/data/gfx/paper/tiny_8x8.png -------------------------------------------------------------------------------- /data/json/resources.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"name": "food", "short": "F"}, 3 | {"name": "wood", "short": "W"}, 4 | {"name": "stones", "short": "S"} 5 | ] -------------------------------------------------------------------------------- /data/json/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "world_size": 1024, 3 | "initial_build_radius": 12, 4 | "initial_population": 10, 5 | "initial_random_terrains": 1000, 6 | "initial_resources": [ 7 | {"resource": "food", "amount": 25}, 8 | {"resource": "wood", "amount": 25}, 9 | {"resource": "stones", "amount": 25} 10 | ], 11 | "random_terrains_count": 6, 12 | "special_card_probability": 0.05, 13 | "random_terrains": [ 14 | "plains", "plains", "plains", "plains", "plains", "plains", "plains", "plains", "plains", "plains", 15 | "plains", "plains", "plains", "plains", "plains", "plains", "plains", "plains", "plains", "plains", 16 | "hills", "hills", "hills", "hills", 17 | "water", "water", "water", "water", "water", "water", 18 | "desert", 19 | "tree", "tree", "tree", "tree", "tree", "tree", 20 | "rock" 21 | ] 22 | } -------------------------------------------------------------------------------- /data/maps/Coastline.json: -------------------------------------------------------------------------------- 1 | { 2 | "terrains": { 3 | "+": 1, 4 | "-": 50, 5 | "^": 6, 6 | "o": 2, 7 | "t": 14, 8 | "~": 20 9 | }, 10 | "map": [ 11 | ".................~.....~................", 12 | "---------------tt~-^^^-~----------------", 13 | "--T------------~~~-^T^t~t---------------", 14 | "-^^---t-------t~t--^^-t~~t--------------", 15 | "-T^-----------t~~-T^T--t~t-------t------", 16 | "-^---------òò-tt~t^^-oot~t--------------", 17 | "-----------òò--t~t^--t~~~o------tt------", 18 | "-----tt--------t~~ttt~~tt------tTTT-----", 19 | "-----ttt------ttt~t~~~ttt-----tTTót-----", 20 | "----tt~~tt---t~~~~~~tttt------TTt-------", 21 | "-----t~~tt--tt~otttttt------------------", 22 | "-----ttttt-tTt~~tTTTt-----TT------------", 23 | "------tttt-TTTt~tTTT--t---TT------------", 24 | "---^^-----TTTtt~tTT-------^-------------", 25 | "--^T^----tTttt~~t--------^--------------", 26 | "---^------^o~~~tt-t----TT---------ttt---", 27 | "----------to~ttt-------TT---------ttt---", 28 | "----------o~~tt--------------------t----", 29 | "----------t~ttt-t-----------------------", 30 | "----------t~ttt-------------------------", 31 | "----------t~~tt---A---------------------", 32 | "---tTT----tt~tt-----------òò---ttt^^----", 33 | "--tTTTT----t~~~t----------òò--ttttt^^---", 34 | "--TTTt--tt--tt~t------t-------t~~~tt^---", 35 | "--------tt---t~------tt--~~----~~~ttt---", 36 | "---~~~~o--++-~~~--------o~~~o---tttt----", 37 | "---~~~~~~~o--~~~~~~~~~--~~~~~~o---------", 38 | "-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--~~~---", 39 | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 40 | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 41 | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 42 | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 43 | ], 44 | "achievements": [ 45 | "landscape-architect", 46 | "fisherman-guild", 47 | "pioneer" 48 | ], 49 | "description": [ 50 | "A medium-sized (40x40) map with a coastline and a river. Plenty of all resources.", 51 | "Available random tiles: 500." 52 | ], 53 | "center": { 54 | "X": 18, 55 | "Y": 20 56 | }, 57 | "initial_terrains": 500 58 | } -------------------------------------------------------------------------------- /data/maps/Desert Valley.json: -------------------------------------------------------------------------------- 1 | { 2 | "terrains": { 3 | "+": 40, 4 | "-": 15, 5 | "^": 1, 6 | "o": 3, 7 | "t": 4, 8 | "~": 4 9 | }, 10 | "map": [ 11 | "....................++++++++++++.........", 12 | "................+++++++òò+++++++++.......", 13 | "..............++++++++òò+++++++++++......", 14 | "............++++ò++++++++++^--------.....", 15 | "..........++++òò++++++++++---tt-------...", 16 | ".........+++++òò+++++++++----~~~~tt----..", 17 | "........++ò+++++++++++++^---t~tt~~~~~---.", 18 | ".......++òò++++++++++++^---t~~tttttt~t---", 19 | "......+++++++++++++++++^---t~tt-----~~~~~", 20 | ".....+++++++++++++òò+++^---t~t-------t---", 21 | "....++++ò++++++++++ò+++---~~~----++^^----", 22 | "....+++òò++++++++++++++--t~tt--+++++++++-", 23 | "...++++ò++++++++++++++--t~~t--^+++òòò++++", 24 | "..+++++++++++++++++++---t~tt--^+++òò+++++", 25 | ".++ò+++++++++òò+++++^---t~tt--^+++ò++++++", 26 | ".++++++++++++òò+++++t----~~~--+++++++++ò+", 27 | ".++++++++++++++++++tt-----t~--+++++++++++", 28 | ".------++++++-------------t~--+++++++++++", 29 | ".---~~~-^+++--ttt--------t~~--+ò+++++++++", 30 | "~~~~~t~t----t~~~~ttt--A--t~t--+ò+++++++++", 31 | ".-ttt-~t---tt~tt~~~~t----t~t-+++++++++++.", 32 | ".-----~~ttt~~~---tt~ttt--~~--+++++++++++.", 33 | ".------~~~~~tt-----~~~~~-~t-^++++++++ò++.", 34 | ".++^^---tt----------ttt~~~--++++++++òò++.", 35 | ".++++^----+++++^-----------+++++++++òò+..", 36 | "..++++++++++++++^^^^+++++++++++++++òò++..", 37 | "...++ò+++ò++++++++++++++òò+++++++++++++..", 38 | "....+++++òòò+++++++++++++ò++++++++++++...", 39 | ".....+++++òòò+++++++++++++++++++++++++...", 40 | "......+++++òò++++++òò++++++++++++ò+++....", 41 | ".......++++++++++++++++++++++++++++++....", 42 | "........++++++++++++++++++++++++++++.....", 43 | ".........++++++++++++++++++ò+++++++......", 44 | "...........++++òò++++++++++++++++........", 45 | ".............+++òò++++++++++++++.........", 46 | "................+++++++++++++............", 47 | "..................++++++++..............." 48 | ], 49 | "achievements": [ 50 | "landscape-architect" 51 | ], 52 | "description": [ 53 | "A medium-sized (40x40) map with a green valley through a vast desert. Very limited on building space.", 54 | "Available random tiles: 500." 55 | ], 56 | "center": { 57 | "X": 22, 58 | "Y": 19 59 | }, 60 | "initial_terrains": 500 61 | } -------------------------------------------------------------------------------- /data/maps/River.json: -------------------------------------------------------------------------------- 1 | { 2 | "terrains": { 3 | "+": 1, 4 | "-": 20, 5 | "^": 4, 6 | "o": 1, 7 | "t": 6, 8 | "~": 6 9 | }, 10 | "map": [ 11 | "......---------~....", 12 | "....-----------~-...", 13 | "...------------~t-..", 14 | "..-----TTT----t~t--.", 15 | ".-----TTTT----t~~t-.", 16 | ".----oTTT-----ot~t--", 17 | "------Tt------ot~t--", 18 | "---------------t~~--", 19 | "--ttt---A------tt~--", 20 | "~~~~~t--------ttt~--", 21 | "---t~~t----t~~~~t~--", 22 | "----t~t---tt~tt~~~--", 23 | ".----~~~~~~~~t------", 24 | "..--------ttt-^^---.", 25 | "...---------^^----..", 26 | "....---tt--------...", 27 | ".....--tt-------....", 28 | "......---------....." 29 | ], 30 | "achievements": [ 31 | "play-the-game" 32 | ], 33 | "description": [ 34 | "A small (20x20) starting area with a river.", 35 | "Available random tiles: 500." 36 | ], 37 | "center": { 38 | "X": 8, 39 | "Y": 8 40 | }, 41 | "initial_terrains": 500 42 | } -------------------------------------------------------------------------------- /data/maps/Rolling Hills.json: -------------------------------------------------------------------------------- 1 | { 2 | "terrains": { 3 | "-": 50, 4 | "^": 20, 5 | "o": 1, 6 | "t": 20, 7 | "~": 6 8 | }, 9 | "map": [ 10 | "TTTTT---TTTT-------ttt-TTT", 11 | "TTTt-----TT-------tTTT--TT", 12 | "TT----t-----------TTt-----", 13 | "TT---TTT----------TT----~~", 14 | "ó----TT------ttT^-----~~~-", 15 | "----tTT--TT-ttTT------~t-t", 16 | "---TTT--TTT-TTTT-----t~--T", 17 | "--TTTT--TT--TTT---^--~~-TT", 18 | "---TT------TTó---TT--~t-TT", 19 | "-----------TT--TTT---~t--T", 20 | "---------T--ó--T^----~~~--", 21 | "tt------TT---------T^--~--", 22 | "tTT----TT---A-----TTT--~--", 23 | "TTT----TT-------óTTT--~~--", 24 | "TTT-----T^------------~---", 25 | "TT--~~~~---------~~~~t~---", 26 | "---~~--~~~----t~~~--~~~--ó", 27 | "~~~~--T--~t~~~~~---------T", 28 | "-----TTT-~~~--------Tó---T", 29 | "---TTTTT--------^--TT-----", 30 | "T--TTt-óó-----TTT-TTt-----", 31 | "TT-----------TTT---TT----T", 32 | "TT-----------TT---TTT--ó-T", 33 | "TT-TT-------TTT---TT----TT", 34 | "-TTTT-------T^----T----TTT", 35 | "-^TT------------------TTTT" 36 | ], 37 | "achievements": [ 38 | "landscape-architect", 39 | "shepherd-guild" 40 | ], 41 | "description": [ 42 | "A small-ish (25x25) map with lots of hills and trees, and a river.", 43 | "Available random tiles: 500." 44 | ], 45 | "center": { 46 | "X": 12, 47 | "Y": 12 48 | }, 49 | "initial_terrains": 500 50 | } -------------------------------------------------------------------------------- /data/maps/Swamp Forest.json: -------------------------------------------------------------------------------- 1 | { 2 | "terrains": { 3 | "-": 40, 4 | "^": 1, 5 | "o": 1, 6 | "t": 25, 7 | "~": 6 8 | }, 9 | "map": [ 10 | "............---............", 11 | "........-----t-----........", 12 | "......---tttttttto---......", 13 | ".....--t~~~tt~~tto-t--.....", 14 | "....--ttttttt~~ttttt~--....", 15 | "...--tttttttttttt^^t~~--...", 16 | "..-~~ttt~~~ttt--tt-tt~t--..", 17 | "..-~~ttt~~~ttt---tttt~tt-..", 18 | ".--ttttttttttt---t~tttttt-.", 19 | ".-tttto^-----tttttttttttt-.", 20 | ".-tttto--ttt--t~~ttt^^t~~-.", 21 | ".-tt~tt-t~~tt-t~~ttt^-t~~-.", 22 | "--tt~tt-tttttt--tottt--tt--", 23 | "--tt~t----tttA---ttt~t--tt-", 24 | "---tttttt-tttt-----t~t--t--", 25 | ".--t-tt~~tttttt--ttttt~-t-.", 26 | ".-tTttt~~tttoottt~~ttt--t-.", 27 | ".-tTott~~~~too-tt~~tt--t--.", 28 | ".-tto-t~~~~tt--tt~~ttttt--.", 29 | "..-tt-tttttttttttttttttt-..", 30 | "..--tt----tTt~~t--t~~ttt-..", 31 | "...--tttt-^^t~~t--ttttt-...", 32 | "....--tt~t^^ttttttttt--....", 33 | ".....--t~tTttttttttt--.....", 34 | "......---ttt-ttttt---......", 35 | "........-----t-----........", 36 | "............---............" 37 | ], 38 | "achievements": [ 39 | "wood-gnome" 40 | ], 41 | "description": [ 42 | "A small-ish (27x27) map with a swampy forest full of ponds.", 43 | "Available random tiles: 500." 44 | ], 45 | "center": { 46 | "X": 13, 47 | "Y": 13 48 | }, 49 | "initial_terrains": 500 50 | } -------------------------------------------------------------------------------- /docs/TILESETS.md: -------------------------------------------------------------------------------- 1 | # Tiny World Tile-sets 2 | 3 | [TODO] -------------------------------------------------------------------------------- /docs/TUTORIAL.md: -------------------------------------------------------------------------------- 1 | # Tiny World Tutorial 2 | 3 | [TODO] -------------------------------------------------------------------------------- /docs/html/iframe.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: #050505; 7 | color: white; 8 | overflow: hidden; 9 | font-family: Arial, Helvetica, sans-serif; 10 | } 11 | 12 | canvas { 13 | max-width: 100%; 14 | } 15 | 16 | #loading { 17 | width: 50px; 18 | height: 50px; 19 | margin: auto; 20 | margin-top: 210px; 21 | } 22 | 23 | .loader { 24 | width: 50px; 25 | height: 50px; 26 | margin: auto; 27 | border: 8px solid #404040; 28 | border-top: 8px solid #ffffff; 29 | border-radius: 50%; 30 | animation: spin 2s linear infinite; 31 | } 32 | 33 | @keyframes spin { 34 | 0% { transform: rotate(0deg); } 35 | 100% { transform: rotate(360deg); } 36 | } -------------------------------------------------------------------------------- /docs/html/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 40 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tiny World 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Tiny World (dev)

27 |
28 | 30 |
31 | 32 |

33 | github.com/mlange-42/tiny-world 34 |
35 | itch.io 36 |

37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/html/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | height: 100%; 7 | width: 100%; 8 | padding: 0; 9 | margin: 0; 10 | background-color: #050505; 11 | color: #FFFFFF; 12 | font-family: Arial, Helvetica, sans-serif; 13 | line-height: 1.5; 14 | } 15 | 16 | p { 17 | margin: 0px 0px 16px 0px; 18 | } 19 | 20 | a { 21 | color: #FFFFFF; 22 | } 23 | 24 | #iframe { 25 | max-width: 100%; 26 | margin-bottom: -6px; 27 | } 28 | 29 | a:visited { 30 | color: #c0c0c0; 31 | } 32 | 33 | .tt { 34 | font-family: 'Lucida Console', monospace; 35 | font-size: 90%; 36 | color: #c0c0c0; 37 | } 38 | 39 | #canvas-container { 40 | display: inline-block; 41 | border: solid white 2px; 42 | min-width: 0px; 43 | max-width: 90%; 44 | overflow: auto; 45 | } 46 | 47 | #canvas { 48 | max-width: 100%; 49 | } 50 | -------------------------------------------------------------------------------- /embed.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "embed" 4 | 5 | //go:embed data 6 | var GameData embed.FS 7 | -------------------------------------------------------------------------------- /game/comp/components.go: -------------------------------------------------------------------------------- 1 | package comp 2 | 3 | import ( 4 | "image" 5 | 6 | "github.com/mlange-42/arche/ecs" 7 | "github.com/mlange-42/tiny-world/game/resource" 8 | "github.com/mlange-42/tiny-world/game/terr" 9 | ) 10 | 11 | type Tile struct { 12 | image.Point 13 | } 14 | 15 | type Terrain struct { 16 | terr.Terrain 17 | } 18 | 19 | type UpdateTick struct { 20 | Tick int64 21 | } 22 | 23 | type Path struct { 24 | Haulers []HaulerEntry 25 | } 26 | 27 | type HaulerEntry struct { 28 | Entity ecs.Entity 29 | YPos float64 30 | } 31 | 32 | type Production struct { 33 | Resource resource.Resource 34 | Amount uint8 35 | Stock uint8 36 | Countdown int 37 | IsHauling bool 38 | HasRequired bool 39 | } 40 | 41 | type Consumption struct { 42 | Amount []uint8 43 | Countdown []int16 44 | IsSatisfied bool 45 | } 46 | 47 | type Population struct { 48 | Pop uint8 49 | } 50 | 51 | type PopulationSupport struct { 52 | Pop uint8 53 | HasRequired bool 54 | } 55 | 56 | type Warehouse struct{} 57 | 58 | type UnlocksTerrain struct{} 59 | 60 | type ProductionMarker struct { 61 | StartTick int64 62 | Resource resource.Resource 63 | } 64 | 65 | type Hauler struct { 66 | Hauls resource.Resource 67 | Home ecs.Entity 68 | Path []Tile 69 | Index int 70 | PathFraction uint8 71 | } 72 | 73 | type HaulerSprite struct { 74 | SpriteIndex int 75 | } 76 | 77 | type RandomSprite struct { 78 | Rand uint16 79 | } 80 | 81 | func (r *RandomSprite) GetRand() uint16 { 82 | if r == nil { 83 | return 0 84 | } 85 | return r.Rand 86 | } 87 | 88 | type BuildRadius struct { 89 | Radius uint8 90 | } 91 | 92 | type CardAnimation struct { 93 | image.Point 94 | Target image.Point 95 | Terrain terr.Terrain 96 | RandSprite uint16 97 | StartTick int64 98 | } 99 | -------------------------------------------------------------------------------- /game/game.go: -------------------------------------------------------------------------------- 1 | package game 2 | 3 | import ( 4 | "github.com/hajimehoshi/ebiten/v2" 5 | "github.com/mlange-42/arche-model/model" 6 | "github.com/mlange-42/tiny-world/game/res" 7 | ) 8 | 9 | // Game container 10 | type Game struct { 11 | Model *model.Model 12 | Screen res.Screen 13 | Mouse res.Mouse 14 | 15 | canvasHelper *canvasHelper 16 | } 17 | 18 | // NewGame returns a new game 19 | func NewGame(mod *model.Model) Game { 20 | return Game{ 21 | Model: mod, 22 | Screen: res.Screen{Image: nil, Width: 0, Height: 0}, 23 | canvasHelper: newCanvasHelper(), 24 | } 25 | } 26 | 27 | // Initialize the game. 28 | func (g *Game) Initialize() { 29 | ebiten.SetWindowSize(1080, 720) 30 | ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled) 31 | ebiten.SetWindowTitle("Tiny World") 32 | } 33 | 34 | // Run the game. 35 | func (g *Game) Run() error { 36 | if err := ebiten.RunGame(g); err != nil { 37 | return err 38 | } 39 | return nil 40 | } 41 | 42 | // Layout the game. 43 | func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { 44 | s := ebiten.DeviceScaleFactor() 45 | return int(float64(outsideWidth) * s), int(float64(outsideHeight) * s) 46 | } 47 | 48 | // Update the game. 49 | func (g *Game) Update() error { 50 | g.updateMouse() 51 | g.Model.Update() 52 | return nil 53 | } 54 | 55 | // Draw the game. 56 | func (g *Game) Draw(screen *ebiten.Image) { 57 | g.Screen.Image = screen 58 | g.Screen.Width = screen.Bounds().Dx() 59 | g.Screen.Height = screen.Bounds().Dy() 60 | g.Model.UpdateUI() 61 | } 62 | 63 | func (g *Game) updateMouse() { 64 | g.Mouse.IsInside = g.canvasHelper.isMouseInside(g.Screen.Width, g.Screen.Height) 65 | } 66 | -------------------------------------------------------------------------------- /game/maps/map.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import "image" 4 | 5 | type Map struct { 6 | Terrains []rune 7 | Data [][]rune 8 | Achievements []string 9 | Description string 10 | Center image.Point 11 | InitialRandomTerrains int 12 | } 13 | -------------------------------------------------------------------------------- /game/math/math.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | func AbsInt(a int) int { 4 | if a < 0 { 5 | return -a 6 | } 7 | return a 8 | } 9 | 10 | func MaxInt(a, b int) int { 11 | if a > b { 12 | return a 13 | } 14 | return b 15 | } 16 | 17 | func MinInt(a, b int) int { 18 | if a < b { 19 | return a 20 | } 21 | return b 22 | } 23 | 24 | func ClampInt(v, min, max int) int { 25 | if v < min { 26 | return min 27 | } 28 | if v > max { 29 | return max 30 | } 31 | return v 32 | } 33 | -------------------------------------------------------------------------------- /game/menu/draw_ui.go: -------------------------------------------------------------------------------- 1 | package menu 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/res" 7 | ) 8 | 9 | // DrawUI is a system to render the user interface. 10 | type DrawUI struct { 11 | screen generic.Resource[res.Screen] 12 | ui generic.Resource[UI] 13 | sprites generic.Resource[res.Sprites] 14 | } 15 | 16 | // InitializeUI the system 17 | func (s *DrawUI) InitializeUI(world *ecs.World) { 18 | s.ui = generic.NewResource[UI](world) 19 | s.screen = generic.NewResource[res.Screen](world) 20 | s.sprites = generic.NewResource[res.Sprites](world) 21 | } 22 | 23 | // UpdateUI the system 24 | func (s *DrawUI) UpdateUI(world *ecs.World) { 25 | screen := s.screen.Get() 26 | ui := s.ui.Get() 27 | 28 | screen.Image.Fill(s.sprites.Get().Background) 29 | 30 | ui.UI().Draw(screen.Image) 31 | } 32 | 33 | // PostUpdateUI the system 34 | func (s *DrawUI) PostUpdateUI(world *ecs.World) {} 35 | 36 | // FinalizeUI the system 37 | func (s *DrawUI) FinalizeUI(world *ecs.World) {} 38 | -------------------------------------------------------------------------------- /game/menu/update_ui.go: -------------------------------------------------------------------------------- 1 | package menu 2 | 3 | import ( 4 | "github.com/hajimehoshi/ebiten/v2" 5 | "github.com/hajimehoshi/ebiten/v2/inpututil" 6 | "github.com/mlange-42/arche/ecs" 7 | "github.com/mlange-42/arche/generic" 8 | ) 9 | 10 | // UpdateUI system. 11 | type UpdateUI struct { 12 | ui generic.Resource[UI] 13 | } 14 | 15 | // Initialize the system 16 | func (s *UpdateUI) Initialize(world *ecs.World) { 17 | s.ui = generic.NewResource[UI](world) 18 | } 19 | 20 | // Update the system 21 | func (s *UpdateUI) Update(world *ecs.World) { 22 | ui := s.ui.Get() 23 | 24 | if ebiten.IsKeyPressed(ebiten.KeyShift) && 25 | ebiten.IsKeyPressed(ebiten.KeyControl) && 26 | ebiten.IsKeyPressed(ebiten.KeyAlt) && 27 | inpututil.IsKeyJustPressed(ebiten.KeyU) { 28 | ui.UnlockAll() 29 | } 30 | 31 | ui.UI().Update() 32 | } 33 | 34 | // Finalize the system 35 | func (s *UpdateUI) Finalize(world *ecs.World) {} 36 | -------------------------------------------------------------------------------- /game/render/card_animation.go: -------------------------------------------------------------------------------- 1 | package render 2 | 3 | import ( 4 | "image" 5 | "math" 6 | 7 | "github.com/hajimehoshi/ebiten/v2" 8 | "github.com/mlange-42/arche/ecs" 9 | "github.com/mlange-42/arche/generic" 10 | "github.com/mlange-42/tiny-world/game/comp" 11 | "github.com/mlange-42/tiny-world/game/res" 12 | "github.com/mlange-42/tiny-world/game/terr" 13 | ) 14 | 15 | // CardAnimation is a system to render card animations. 16 | type CardAnimation struct { 17 | MaxOffset int 18 | Duration int 19 | 20 | time generic.Resource[res.GameTick] 21 | screen generic.Resource[res.Screen] 22 | sprites generic.Resource[res.Sprites] 23 | view generic.Resource[res.View] 24 | 25 | filter generic.Filter1[comp.CardAnimation] 26 | 27 | toRemove []ecs.Entity 28 | } 29 | 30 | // InitializeUI the system 31 | func (s *CardAnimation) InitializeUI(world *ecs.World) { 32 | s.time = generic.NewResource[res.GameTick](world) 33 | s.screen = generic.NewResource[res.Screen](world) 34 | s.sprites = generic.NewResource[res.Sprites](world) 35 | s.view = generic.NewResource[res.View](world) 36 | 37 | s.filter = *generic.NewFilter1[comp.CardAnimation]() 38 | } 39 | 40 | // UpdateUI the system 41 | func (s *CardAnimation) UpdateUI(world *ecs.World) { 42 | tick := s.time.Get().RenderTick 43 | sprites := s.sprites.Get() 44 | canvas := s.screen.Get() 45 | img := canvas.Image 46 | 47 | op := ebiten.DrawImageOptions{} 48 | 49 | drawSprite := func(point *image.Point, t terr.Terrain, rnd int) { 50 | below := terr.Properties[t].TerrainBelow 51 | 52 | op.GeoM.Reset() 53 | op.GeoM.Translate(float64(point.X), float64(point.Y)) 54 | 55 | for _, tr := range below { 56 | bIdx := sprites.GetTerrainIndex(tr) 57 | sp := sprites.Get(bIdx) 58 | img.DrawImage(sp, &op) 59 | } 60 | 61 | idx := sprites.GetTerrainIndex(t) 62 | sp := sprites.GetRand(idx, 0, rnd) 63 | img.DrawImage(sp, &op) 64 | } 65 | 66 | query := s.filter.Query(world) 67 | for query.Next() { 68 | card := query.Get() 69 | 70 | passed := tick - card.StartTick 71 | if passed > int64(s.Duration) { 72 | s.toRemove = append(s.toRemove, query.Entity()) 73 | continue 74 | } 75 | off := s.MaxOffset * int(passed) / s.Duration 76 | diff := card.Target.Sub(image.Pt(sprites.TileWidth/2, sprites.TileHeight/2)).Sub(card.Point) 77 | ln := 1 / math.Sqrt(float64(diff.X*diff.X+diff.Y*diff.Y)) 78 | 79 | point := image.Pt(card.X+int(float64(diff.X*off)*ln), card.Y+int(float64(diff.Y*off)*ln)) 80 | drawSprite(&point, card.Terrain, int(card.RandSprite)) 81 | } 82 | 83 | for _, e := range s.toRemove { 84 | world.RemoveEntity(e) 85 | } 86 | s.toRemove = s.toRemove[:0] 87 | } 88 | 89 | // PostUpdateUI the system 90 | func (s *CardAnimation) PostUpdateUI(world *ecs.World) {} 91 | 92 | // FinalizeUI the system 93 | func (s *CardAnimation) FinalizeUI(world *ecs.World) {} 94 | -------------------------------------------------------------------------------- /game/render/center_view.go: -------------------------------------------------------------------------------- 1 | package render 2 | 3 | import ( 4 | "image" 5 | 6 | "github.com/mlange-42/arche/ecs" 7 | "github.com/mlange-42/arche/generic" 8 | "github.com/mlange-42/tiny-world/game/res" 9 | ) 10 | 11 | // UI is a system to render the user interface. 12 | type CenterView struct { 13 | view generic.Resource[res.View] 14 | screen generic.Resource[res.Screen] 15 | terrain generic.Resource[res.Terrain] 16 | 17 | isInitialized bool 18 | } 19 | 20 | // InitializeUI the system 21 | func (s *CenterView) InitializeUI(world *ecs.World) { 22 | s.view = generic.NewResource[res.View](world) 23 | s.screen = generic.NewResource[res.Screen](world) 24 | s.terrain = generic.NewResource[res.Terrain](world) 25 | } 26 | 27 | // UpdateUI the system 28 | func (s *CenterView) UpdateUI(world *ecs.World) { 29 | if !s.isInitialized { 30 | view := s.view.Get() 31 | screen := s.screen.Get() 32 | terrain := s.terrain.Get() 33 | view.Center(image.Point{terrain.Width() / 2, terrain.Height() / 2}, screen.Width, screen.Height) 34 | s.isInitialized = true 35 | } 36 | } 37 | 38 | // PostUpdateUI the system 39 | func (s *CenterView) PostUpdateUI(world *ecs.World) {} 40 | 41 | // FinalizeUI the system 42 | func (s *CenterView) FinalizeUI(world *ecs.World) {} 43 | -------------------------------------------------------------------------------- /game/render/hauler_paths.go: -------------------------------------------------------------------------------- 1 | package render 2 | 3 | import ( 4 | "image/color" 5 | 6 | "github.com/hajimehoshi/ebiten/v2/vector" 7 | "github.com/mlange-42/arche/ecs" 8 | "github.com/mlange-42/arche/generic" 9 | "github.com/mlange-42/tiny-world/game/comp" 10 | "github.com/mlange-42/tiny-world/game/res" 11 | ) 12 | 13 | // HaulerPaths is a system to render paths. 14 | type HaulerPaths struct { 15 | screen generic.Resource[res.Screen] 16 | view generic.Resource[res.View] 17 | update generic.Resource[res.UpdateInterval] 18 | 19 | filter generic.Filter1[comp.Hauler] 20 | } 21 | 22 | // InitializeUI the system 23 | func (s *HaulerPaths) InitializeUI(world *ecs.World) { 24 | s.screen = generic.NewResource[res.Screen](world) 25 | s.view = generic.NewResource[res.View](world) 26 | s.update = generic.NewResource[res.UpdateInterval](world) 27 | 28 | s.filter = *generic.NewFilter1[comp.Hauler]() 29 | } 30 | 31 | // UpdateUI the system 32 | func (s *HaulerPaths) UpdateUI(world *ecs.World) { 33 | view := s.view.Get() 34 | update := s.update.Get() 35 | off := view.Offset() 36 | canvas := s.screen.Get() 37 | img := canvas.Image 38 | 39 | h := view.TileHeight / 2 40 | z := float32(view.Zoom) 41 | col := color.RGBA{60, 60, 255, 255} 42 | 43 | query := s.filter.Query(world) 44 | for query.Next() { 45 | haul := query.Get() 46 | path := haul.Path 47 | n := len(path) - 1 48 | for i := 0; i < n; i++ { 49 | p1 := path[i] 50 | p2 := path[i+1] 51 | 52 | point1 := view.TileToGlobal(p1.X, p1.Y) 53 | point2 := view.TileToGlobal(p2.X, p2.Y) 54 | 55 | x1 := float32(point1.X)*z - float32(off.X) 56 | y1 := float32(point1.Y-h)*z - float32(off.Y) 57 | x2 := float32(point2.X)*z - float32(off.X) 58 | y2 := float32(point2.Y-h)*z - float32(off.Y) 59 | 60 | //vector.StrokeLine(img, x1, y1, x2, y2, 2, col, false) 61 | 62 | if i != n-1 { 63 | continue 64 | } 65 | 66 | dt := float32(haul.PathFraction) / float32(update.Interval) 67 | xx := x1*dt + x2*(1-dt) 68 | yy := y1*dt + y2*(1-dt) 69 | 70 | vector.DrawFilledCircle(img, xx, yy, 4, col, false) 71 | } 72 | } 73 | } 74 | 75 | // PostUpdateUI the system 76 | func (s *HaulerPaths) PostUpdateUI(world *ecs.World) {} 77 | 78 | // FinalizeUI the system 79 | func (s *HaulerPaths) FinalizeUI(world *ecs.World) {} 80 | -------------------------------------------------------------------------------- /game/render/ui.go: -------------------------------------------------------------------------------- 1 | package render 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/res" 7 | ) 8 | 9 | // UI is a system to render the user interface. 10 | type UI struct { 11 | screen generic.Resource[res.Screen] 12 | ui generic.Resource[res.UI] 13 | } 14 | 15 | // InitializeUI the system 16 | func (s *UI) InitializeUI(world *ecs.World) { 17 | s.ui = generic.NewResource[res.UI](world) 18 | s.screen = generic.NewResource[res.Screen](world) 19 | } 20 | 21 | // UpdateUI the system 22 | func (s *UI) UpdateUI(world *ecs.World) { 23 | screen := s.screen.Get() 24 | ui := s.ui.Get() 25 | 26 | ui.Draw(screen.Image) 27 | } 28 | 29 | // PostUpdateUI the system 30 | func (s *UI) PostUpdateUI(world *ecs.World) {} 31 | 32 | // FinalizeUI the system 33 | func (s *UI) FinalizeUI(world *ecs.World) {} 34 | -------------------------------------------------------------------------------- /game/res/editor.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | // EditorMode resource, indicating editor mode. 4 | type EditorMode struct { 5 | IsEditor bool 6 | } 7 | -------------------------------------------------------------------------------- /game/res/fonts.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import ( 4 | "io/fs" 5 | "log" 6 | 7 | "github.com/hajimehoshi/ebiten/v2/text" 8 | "golang.org/x/image/font" 9 | "golang.org/x/image/font/opentype" 10 | "golang.org/x/image/font/sfnt" 11 | ) 12 | 13 | const fontFile = "data/fonts/LessRoundBox.ttf" 14 | 15 | // Fonts resource for access to UI fonts. 16 | type Fonts struct { 17 | Default font.Face 18 | Title font.Face 19 | } 20 | 21 | func NewFonts(fSys fs.FS) Fonts { 22 | content, err := fs.ReadFile(fSys, fontFile) 23 | if err != nil { 24 | log.Fatal("error loading font file: ", err) 25 | } 26 | tt, err := opentype.Parse(content) 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | 31 | defaultFace, err := makeSize(tt, 22) 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | titleFace, err := makeSize(tt, 48) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | 40 | return Fonts{ 41 | Default: defaultFace, 42 | Title: titleFace, 43 | } 44 | } 45 | 46 | func makeSize(tt *sfnt.Font, size int) (font.Face, error) { 47 | const dpi = 72 48 | fontFace, err := opentype.NewFace(tt, &opentype.FaceOptions{ 49 | Size: float64(size), 50 | DPI: dpi, 51 | Hinting: font.HintingFull, 52 | }) 53 | if err != nil { 54 | return nil, err 55 | } 56 | fontFace = text.FaceWithLineHeight(fontFace, float64(size)) 57 | return fontFace, nil 58 | } 59 | -------------------------------------------------------------------------------- /game/res/game_speed.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | // GameSpeed resource. 4 | type GameSpeed struct { 5 | // Is the game paused? 6 | Pause bool 7 | // Game speed as an exponent for base 2. s = 2^Speed 8 | Speed int8 9 | // Minimum game speed, as an exponent for base 2. 10 | MinSpeed int8 11 | // Maximum game speed, as an exponent for base 2. 12 | MaxSpeed int8 13 | } 14 | 15 | // GameTick resource. 16 | type GameTick struct { 17 | // Current update tick. Stops when the game is paused. 18 | Tick int64 19 | // Current render tick. Does not stop when the game is paused. 20 | RenderTick int64 21 | } 22 | -------------------------------------------------------------------------------- /game/res/grid.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | // Grid data structure 8 | type Grid[T comparable] struct { 9 | data []T 10 | width int 11 | height int 12 | } 13 | 14 | // NewGrid returns a new Grid. 15 | func NewGrid[T comparable](width, height int) Grid[T] { 16 | return Grid[T]{ 17 | data: make([]T, width*height), 18 | width: width, 19 | height: height, 20 | } 21 | } 22 | 23 | // Get a value from the Grid. 24 | func (g *Grid[T]) Get(x, y int) T { 25 | idx := x*g.height + y 26 | return g.data[idx] 27 | } 28 | 29 | // Get a pointer to a value from the Grid. 30 | func (g *Grid[T]) GetPointer(x, y int) *T { 31 | idx := x*g.height + y 32 | return &g.data[idx] 33 | } 34 | 35 | // Set a value in the grid. 36 | func (g *Grid[T]) Set(x, y int, value T) { 37 | idx := x*g.height + y 38 | g.data[idx] = value 39 | } 40 | 41 | // Fill the grid with a value. 42 | func (g *Grid[T]) Fill(value T) { 43 | for i := range g.data { 44 | g.data[i] = value 45 | } 46 | } 47 | 48 | // Width of the Grid. 49 | func (g *Grid[T]) Width() int { 50 | return g.width 51 | } 52 | 53 | // Height of the Grid. 54 | func (g *Grid[T]) Height() int { 55 | return g.height 56 | } 57 | 58 | // Contains returns whether the grid contains the given cell. 59 | func (g *Grid[T]) Contains(x, y int) bool { 60 | return x >= 0 && y >= 0 && x < g.width && y < g.height 61 | } 62 | 63 | // Clamp coordinates to be inside the grid. 64 | func (g *Grid[T]) Clamp(x, y int) (int, int) { 65 | if x < 0 { 66 | x = 0 67 | } 68 | if y < 0 { 69 | y = 0 70 | } 71 | if x >= g.width { 72 | x = g.width - 1 73 | } 74 | if y >= g.height { 75 | y = g.height - 1 76 | } 77 | return x, y 78 | } 79 | 80 | func (g *Grid[T]) MarshalJSON() ([]byte, error) { 81 | helper := gridHelper[T]{ 82 | Data: g.data, 83 | Width: g.width, 84 | Height: g.height, 85 | } 86 | return json.Marshal(helper) 87 | } 88 | 89 | func (g *Grid[T]) UnmarshalJSON(data []byte) error { 90 | helper := gridHelper[T]{} 91 | if err := json.Unmarshal(data, &helper); err != nil { 92 | return err 93 | } 94 | g.data = helper.Data 95 | g.width = helper.Width 96 | g.height = helper.Height 97 | 98 | return nil 99 | } 100 | 101 | type gridHelper[T comparable] struct { 102 | Data []T 103 | Width int 104 | Height int 105 | } 106 | -------------------------------------------------------------------------------- /game/res/image.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import "github.com/hajimehoshi/ebiten/v2" 4 | 5 | // Screen resource for drawing. 6 | type Screen struct { 7 | // The screen image. 8 | Image *ebiten.Image 9 | // Current screen width. 10 | Width int 11 | // Current screen height. 12 | Height int 13 | } 14 | -------------------------------------------------------------------------------- /game/res/mouse.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | // Mouse resource. 4 | type Mouse struct { 5 | // whether the mouse is inside the game window. 6 | IsInside bool 7 | } 8 | -------------------------------------------------------------------------------- /game/res/production.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import ( 4 | "github.com/mlange-42/tiny-world/game/resource" 5 | ) 6 | 7 | // Production, accumulated globally. 8 | type Production struct { 9 | // Current production, indexed by [resource.Resource]. 10 | Prod []int 11 | // Current consumption, indexed by [resource.Resource]. 12 | Cons []int 13 | } 14 | 15 | // NewProduction creates a new Production resource. 16 | func NewProduction() Production { 17 | return Production{ 18 | Prod: make([]int, len(resource.Properties)), 19 | Cons: make([]int, len(resource.Properties)), 20 | } 21 | } 22 | 23 | // Reset all production and consumption zo zero. 24 | func (p *Production) Reset() { 25 | for i := range resource.Properties { 26 | p.Prod[i] = 0 27 | p.Cons[i] = 0 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /game/res/random_terrains.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import "github.com/mlange-42/tiny-world/game/terr" 4 | 5 | type RandomTerrains struct { 6 | Terrains []terr.Terrain 7 | AllowRemove []bool 8 | TotalAvailable int 9 | TotalPlaced int 10 | } 11 | -------------------------------------------------------------------------------- /game/res/save_event.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | // SaveEvent resource 4 | type SaveEvent struct { 5 | // Whether the save button was clicked in this tick. 6 | ShouldSave bool 7 | // Whether the game should quit and show the main menu. 8 | ShouldQuit bool 9 | // Whether the save as map button was clicked in this tick. 10 | ShouldSaveMap bool 11 | } 12 | -------------------------------------------------------------------------------- /game/res/save_time.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import "time" 4 | 5 | // SaveTime resource, containing the time when the game was saved. 6 | type SaveTime struct { 7 | Time time.Time 8 | } 9 | -------------------------------------------------------------------------------- /game/res/selection.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import "github.com/mlange-42/tiny-world/game/terr" 4 | 5 | // Selection from the build toolbar. 6 | type Selection struct { 7 | // Selected terrain type. 8 | BuildType terr.Terrain 9 | // ID of the selected button. 10 | ButtonID int 11 | // Random sprite index of the selected button. 12 | RandSprite uint16 13 | // Whether a new random sprite index should be draw on placement. 14 | Randomize bool 15 | // Whether a special tile has been selected. 16 | AllowRemove bool 17 | } 18 | 19 | // SetBuild sets all fields to the given selection. 20 | func (s *Selection) SetBuild(build terr.Terrain, button int, randSprite uint16, randomize, allowRemove bool) { 21 | s.BuildType = build 22 | s.ButtonID = button 23 | s.RandSprite = randSprite 24 | s.Randomize = randomize 25 | s.AllowRemove = allowRemove 26 | } 27 | 28 | // Reset to select nothing. 29 | func (s *Selection) Reset() { 30 | s.BuildType = terr.Air 31 | s.ButtonID = -1 32 | } 33 | -------------------------------------------------------------------------------- /game/res/stock.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import ( 4 | "github.com/mlange-42/tiny-world/game/resource" 5 | "github.com/mlange-42/tiny-world/game/terr" 6 | ) 7 | 8 | // Stock resource, holding global stock information. 9 | type Stock struct { 10 | // Total storage capacity, indexed by [resource.Resource]. 11 | Cap []int 12 | // Total storage, indexed by [resource.Resource]. 13 | Res []int 14 | // Total production ever delivered to storage, indexed by [resource.Resource]. 15 | Total []int 16 | 17 | // Total population. 18 | Population int 19 | // Total population limit. 20 | MaxPopulation int 21 | } 22 | 23 | // NewStock creates a new Stock resource with the given initial resources. 24 | func NewStock(initial []int) Stock { 25 | if len(initial) != len(resource.Properties) { 26 | panic("initial resources don't match number of actual resources") 27 | } 28 | return Stock{ 29 | Cap: make([]int, len(resource.Properties)), 30 | Res: initial, 31 | Total: make([]int, len(resource.Properties)), 32 | } 33 | } 34 | 35 | func (s *Stock) AddResources(res resource.Resource, amount int) { 36 | s.Res[res] += amount 37 | s.Total[res] += amount 38 | } 39 | 40 | // CanPay checks whether there are sufficient resources in the stock to pay the given amounts. 41 | func (s *Stock) CanPay(cost []terr.ResourceAmount) bool { 42 | for _, c := range cost { 43 | if s.Res[c.Resource] < int(c.Amount) { 44 | return false 45 | } 46 | } 47 | return true 48 | } 49 | 50 | // Pay the given amounts be subtracting them from the stock. 51 | func (s *Stock) Pay(cost []terr.ResourceAmount) { 52 | for _, c := range cost { 53 | s.Res[c.Resource] -= int(c.Amount) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /game/res/update.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | // UpdateInterval resource. 4 | type UpdateInterval struct { 5 | // The interval between updates of entities, in game ticks. Usually equal to TPS. 6 | Interval int64 7 | // Number of intervals used in (production) countdowns. Usually 60, resulting in 1 minute. 8 | Countdown int 9 | } 10 | -------------------------------------------------------------------------------- /game/res/world_bounds.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | import "image" 4 | 5 | // WorldBounds contain the bounding box of the currently built world. 6 | // Used to limit scrolling/panning. 7 | type WorldBounds struct { 8 | image.Rectangle 9 | } 10 | 11 | // Contains checks whether a pont is inside the bounds. 12 | func (b *WorldBounds) Contains(p image.Point) bool { 13 | return b.Min.X <= p.X && p.X <= b.Max.X && 14 | b.Min.Y <= p.Y && p.Y <= b.Max.Y 15 | } 16 | 17 | // AddPoint extends the bounds sp that they contain the given point. 18 | func (b *WorldBounds) AddPoint(p image.Point) { 19 | if !b.Contains(p) { 20 | if p.X < b.Min.X { 21 | b.Min.X = p.X 22 | } 23 | if p.Y < b.Min.Y { 24 | b.Min.Y = p.Y 25 | } 26 | if p.X > b.Max.X { 27 | b.Max.X = p.X 28 | } 29 | if p.Y > b.Max.Y { 30 | b.Max.Y = p.Y 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /game/resource/resources.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "fmt" 5 | "io/fs" 6 | 7 | "github.com/mlange-42/tiny-world/cmd/util" 8 | ) 9 | 10 | type Resource uint8 11 | 12 | type Resources uint32 13 | 14 | func (d *Resources) Set(dir Resource) { 15 | *d |= (1 << dir) 16 | } 17 | 18 | func (d *Resources) Unset(dir Resource) { 19 | *d &= ^(1 << dir) 20 | } 21 | 22 | // Contains checks whether all the argument's bits are contained in this mask. 23 | func (d Resources) Contains(dir Resource) bool { 24 | bits := Resources(1 << dir) 25 | return (bits & d) == bits 26 | } 27 | 28 | type ResourceProps struct { 29 | Name string `json:"name"` 30 | Short string `json:"short"` 31 | } 32 | 33 | var Properties []ResourceProps 34 | 35 | func ResourceID(name string) (Resource, bool) { 36 | t, ok := idLookup[name] 37 | return t, ok 38 | } 39 | 40 | var idLookup map[string]Resource 41 | 42 | func Prepare(f fs.FS, file string) { 43 | props := []ResourceProps{} 44 | err := util.FromJsonFs(f, file, &props) 45 | if err != nil { 46 | panic(err) 47 | } 48 | 49 | idLookup = map[string]Resource{} 50 | for i, t := range props { 51 | idLookup[t.Name] = Resource(i) 52 | } 53 | Properties = props 54 | } 55 | 56 | func ToResources(res ...string) Resources { 57 | var ret Resources 58 | for _, r := range res { 59 | id, ok := idLookup[r] 60 | if !ok { 61 | panic(fmt.Sprintf("unknown resource '%s'", r)) 62 | } 63 | ret.Set(id) 64 | } 65 | return ret 66 | } 67 | 68 | func ToResource(r string) Resource { 69 | id, ok := idLookup[r] 70 | if !ok { 71 | panic(fmt.Sprintf("unknown resource '%s'", r)) 72 | } 73 | return id 74 | } 75 | -------------------------------------------------------------------------------- /game/run_nowasm.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | 3 | package game 4 | 5 | import ( 6 | "github.com/hajimehoshi/ebiten/v2" 7 | ) 8 | 9 | type canvasHelper struct{} 10 | 11 | func newCanvasHelper() *canvasHelper { 12 | return &canvasHelper{} 13 | } 14 | 15 | func (c *canvasHelper) isMouseInside(width, height int) bool { 16 | x, y := ebiten.CursorPosition() 17 | return x >= 0 && y >= 0 && x < width && y < height 18 | } 19 | -------------------------------------------------------------------------------- /game/run_wasm.go: -------------------------------------------------------------------------------- 1 | //go:build js 2 | 3 | package game 4 | 5 | import ( 6 | "syscall/js" 7 | ) 8 | 9 | type canvasHelper struct { 10 | doc js.Value 11 | canvas js.Value 12 | mouseInside bool 13 | } 14 | 15 | func newCanvasHelper() *canvasHelper { 16 | doc := js.Global().Get("document") 17 | canvas := doc.Call("getElementsByTagName", "canvas").Index(0) 18 | 19 | helper := canvasHelper{ 20 | doc: doc, 21 | canvas: canvas, 22 | } 23 | 24 | canvas.Set("onmouseleave", js.FuncOf(helper.onMouseLeave)) 25 | canvas.Set("onmouseenter", js.FuncOf(helper.onMouseEnter)) 26 | 27 | return &helper 28 | } 29 | 30 | func (c *canvasHelper) isMouseInside(width, height int) bool { 31 | _, _ = width, height 32 | return c.mouseInside 33 | } 34 | 35 | func (c *canvasHelper) onMouseEnter(this js.Value, args []js.Value) interface{} { 36 | c.mouseInside = true 37 | return nil 38 | } 39 | 40 | func (c *canvasHelper) onMouseLeave(this js.Value, args []js.Value) interface{} { 41 | c.mouseInside = false 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /game/save/load_nowasm.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | 3 | package save 4 | 5 | import ( 6 | "encoding/json" 7 | "os" 8 | "path" 9 | "path/filepath" 10 | "strings" 11 | 12 | serde "github.com/mlange-42/arche-serde" 13 | "github.com/mlange-42/arche/ecs" 14 | ) 15 | 16 | func loadWorld(world *ecs.World, folder, name string) error { 17 | jsData, err := os.ReadFile(path.Join(folder, name) + ".json") 18 | if err != nil { 19 | return err 20 | } 21 | 22 | return serde.Deserialize(jsData, world) 23 | } 24 | 25 | func loadSaveTime(folder, name string) (saveTime, error) { 26 | jsData, err := os.ReadFile(path.Join(folder, name) + ".json") 27 | if err != nil { 28 | return saveTime{}, err 29 | } 30 | helper := saveGameInfo{} 31 | err = json.Unmarshal(jsData, &helper) 32 | if err != nil { 33 | return saveTime{}, err 34 | } 35 | return helper.Resources.SaveTime, nil 36 | } 37 | 38 | func loadAchievements(file string, completed *[]string) error { 39 | jsData, err := os.ReadFile(file) 40 | if err != nil { 41 | return err 42 | } 43 | return json.Unmarshal(jsData, completed) 44 | } 45 | 46 | func listGames(folder string) ([]SaveGame, error) { 47 | games := []SaveGame{} 48 | 49 | files, err := os.ReadDir(folder) 50 | if err != nil { 51 | return nil, nil 52 | } 53 | 54 | for _, file := range files { 55 | if file.IsDir() { 56 | continue 57 | } 58 | ext := filepath.Ext(file.Name()) 59 | if ext == ".json" { 60 | base := strings.TrimSuffix(file.Name(), ".json") 61 | info, err := loadSaveTime(folder, base) 62 | if err != nil { 63 | return nil, err 64 | } 65 | games = append(games, SaveGame{ 66 | Name: base, 67 | Time: info.Time, 68 | }) 69 | } 70 | } 71 | return games, nil 72 | } 73 | 74 | func listMapsLocal(folder string) ([]MapLocation, error) { 75 | maps := []MapLocation{} 76 | 77 | files, err := os.ReadDir(folder) 78 | if err != nil { 79 | return nil, nil 80 | } 81 | 82 | for _, file := range files { 83 | if file.IsDir() { 84 | continue 85 | } 86 | ext := filepath.Ext(file.Name()) 87 | if ext == ".json" { 88 | base := strings.TrimSuffix(file.Name(), ".json") 89 | maps = append(maps, MapLocation{Name: base, IsEmbedded: false}) 90 | } 91 | } 92 | return maps, nil 93 | } 94 | 95 | func loadMapLocal(folder string, name string) (string, error) { 96 | mapData, err := os.ReadFile(path.Join(folder, name) + ".json") 97 | if err != nil { 98 | return "", err 99 | } 100 | 101 | return string(mapData), nil 102 | } 103 | -------------------------------------------------------------------------------- /game/save/load_wasm.go: -------------------------------------------------------------------------------- 1 | //go:build js 2 | 3 | package save 4 | 5 | import ( 6 | "encoding/json" 7 | "strings" 8 | "syscall/js" 9 | 10 | serde "github.com/mlange-42/arche-serde" 11 | "github.com/mlange-42/arche/ecs" 12 | ) 13 | 14 | func loadWorld(world *ecs.World, folder, name string) error { 15 | _ = folder 16 | 17 | storage := js.Global().Get("localStorage") 18 | jsData := storage.Call("getItem", saveGamePrefix+name) 19 | 20 | return serde.Deserialize([]byte(jsData.String()), world) 21 | } 22 | 23 | func loadSaveTime(folder, name string) (saveTime, error) { 24 | _ = folder 25 | 26 | storage := js.Global().Get("localStorage") 27 | jsData := storage.Call("getItem", saveGamePrefix+name) 28 | 29 | helper := saveGameInfo{} 30 | err := json.Unmarshal([]byte(jsData.String()), &helper) 31 | if err != nil { 32 | return saveTime{}, err 33 | } 34 | return helper.Resources.SaveTime, nil 35 | } 36 | 37 | func loadAchievements(file string, completed *[]string) error { 38 | _ = file 39 | 40 | storage := js.Global().Get("localStorage") 41 | jsData := storage.Call("getItem", achievementsKey) 42 | 43 | if jsData.IsNull() { 44 | return nil 45 | } 46 | 47 | return json.Unmarshal([]byte(jsData.String()), completed) 48 | } 49 | 50 | func listGames(folder string) ([]SaveGame, error) { 51 | _ = folder 52 | games := []SaveGame{} 53 | 54 | storage := js.Global().Get("localStorage") 55 | 56 | cnt := storage.Get("length").Int() 57 | for i := 0; i < cnt; i++ { 58 | key := storage.Call("key", i).String() 59 | if strings.HasPrefix(key, saveGamePrefix) { 60 | name := strings.TrimPrefix(key, saveGamePrefix) 61 | info, err := loadSaveTime(folder, name) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | games = append(games, SaveGame{ 67 | Name: name, 68 | Time: info.Time, 69 | }) 70 | } 71 | } 72 | 73 | return games, nil 74 | } 75 | 76 | func listMapsLocal(folder string) ([]MapLocation, error) { 77 | _ = folder 78 | maps := []MapLocation{} 79 | 80 | storage := js.Global().Get("localStorage") 81 | 82 | cnt := storage.Get("length").Int() 83 | for i := 0; i < cnt; i++ { 84 | key := storage.Call("key", i).String() 85 | if strings.HasPrefix(key, saveMapPrefix) { 86 | maps = append(maps, MapLocation{Name: strings.TrimPrefix(key, saveMapPrefix), IsEmbedded: false}) 87 | } 88 | } 89 | 90 | return maps, nil 91 | } 92 | 93 | func loadMapLocal(folder string, name string) (string, error) { 94 | _ = folder 95 | storage := js.Global().Get("localStorage") 96 | mapData := storage.Call("getItem", saveMapPrefix+name) 97 | 98 | return mapData.String(), nil 99 | } 100 | -------------------------------------------------------------------------------- /game/save/save_nowasm.go: -------------------------------------------------------------------------------- 1 | //go:build !js 2 | 3 | package save 4 | 5 | import ( 6 | "encoding/json" 7 | "os" 8 | "path" 9 | "path/filepath" 10 | ) 11 | 12 | func saveToFile(folder, name string, jsData []byte) error { 13 | file := path.Join(folder, name) + ".json" 14 | dir := filepath.Dir(file) 15 | err := os.MkdirAll(dir, os.ModePerm) 16 | if err != nil { 17 | return err 18 | } 19 | 20 | f, err := os.Create(file) 21 | if err != nil { 22 | return err 23 | } 24 | defer f.Close() 25 | 26 | f.Write(jsData) 27 | 28 | return nil 29 | } 30 | 31 | func saveAchievements(file string, completed []string) error { 32 | jsData, err := json.MarshalIndent(completed, "", " ") 33 | if err != nil { 34 | return err 35 | } 36 | 37 | dir := filepath.Dir(file) 38 | err = os.MkdirAll(dir, os.ModePerm) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | f, err := os.Create(file) 44 | if err != nil { 45 | return err 46 | } 47 | defer f.Close() 48 | 49 | f.Write(jsData) 50 | 51 | return nil 52 | } 53 | 54 | func deleteGame(folder, name string) error { 55 | file := path.Join(folder, name) + ".json" 56 | return os.Remove(file) 57 | } 58 | 59 | func saveMapToFile(folder, name string, mapData string) error { 60 | file := path.Join(folder, name) + ".json" 61 | dir := filepath.Dir(file) 62 | err := os.MkdirAll(dir, os.ModePerm) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | f, err := os.Create(file) 68 | if err != nil { 69 | return err 70 | } 71 | defer f.Close() 72 | 73 | f.WriteString(mapData) 74 | 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /game/save/save_wasm.go: -------------------------------------------------------------------------------- 1 | //go:build js 2 | 3 | package save 4 | 5 | import ( 6 | "encoding/json" 7 | "syscall/js" 8 | ) 9 | 10 | // Prefices for browser localStorage keys 11 | const ( 12 | saveGamePrefix = "mlange-42/tiny-world/save/" 13 | saveMapPrefix = "mlange-42/tiny-world/maps/" 14 | achievementsKey = "mlange-42/tiny-world/achievements" 15 | ) 16 | 17 | func saveToFile(folder, name string, jsData []byte) error { 18 | _ = folder 19 | 20 | data := js.ValueOf(string(jsData)) 21 | storage := js.Global().Get("localStorage") 22 | storage.Call("setItem", saveGamePrefix+name, data) 23 | 24 | return nil 25 | } 26 | 27 | func saveAchievements(file string, completed []string) error { 28 | _ = file 29 | 30 | jsData, err := json.MarshalIndent(completed, "", " ") 31 | if err != nil { 32 | return err 33 | } 34 | 35 | data := js.ValueOf(string(jsData)) 36 | storage := js.Global().Get("localStorage") 37 | storage.Call("setItem", achievementsKey, data) 38 | 39 | return nil 40 | } 41 | 42 | func deleteGame(folder, name string) error { 43 | _ = folder 44 | 45 | storage := js.Global().Get("localStorage") 46 | storage.Delete(saveGamePrefix + name) 47 | return nil 48 | } 49 | 50 | func saveMapToFile(folder, name string, mapData string) error { 51 | _ = folder 52 | 53 | data := js.ValueOf(mapData) 54 | storage := js.Global().Get("localStorage") 55 | storage.Call("setItem", saveMapPrefix+name, data) 56 | 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /game/save/types.go: -------------------------------------------------------------------------------- 1 | package save 2 | 3 | import ( 4 | "image" 5 | "time" 6 | ) 7 | 8 | type LoadType uint8 9 | 10 | const ( 11 | LoadTypeNone LoadType = iota 12 | LoadTypeGame 13 | LoadTypeMap 14 | ) 15 | 16 | type MapLocation struct { 17 | Name string 18 | IsEmbedded bool 19 | } 20 | 21 | type SaveGame struct { 22 | Name string 23 | Time time.Time 24 | } 25 | 26 | type saveGameInfo struct { 27 | Resources saveGameResources 28 | } 29 | 30 | type saveGameResources struct { 31 | SaveTime saveTime `json:"res.SaveTime"` 32 | } 33 | 34 | type saveTime struct { 35 | Time time.Time 36 | } 37 | 38 | type MapInfo struct { 39 | Achievements []string 40 | Description string 41 | } 42 | 43 | type mapInfoJs struct { 44 | Achievements []string `json:"achievements"` 45 | Description []string `json:"description"` 46 | } 47 | 48 | type mapJs struct { 49 | Terrains map[string]int `json:"terrains"` 50 | Map []string `json:"map"` 51 | Achievements []string `json:"achievements"` 52 | Description []string `json:"description"` 53 | Center image.Point `json:"center"` 54 | InitialRandomTerrains int `json:"initial_terrains"` 55 | } 56 | -------------------------------------------------------------------------------- /game/sprites/sprites.go: -------------------------------------------------------------------------------- 1 | package sprites 2 | 3 | const ( 4 | BorderInner = "border_inner" 5 | BorderOuter = "border_outer" 6 | 7 | CursorDenied = "cursor_denied" 8 | CursorOk = "cursor_ok" 9 | CursorNeutral = "cursor_neutral" 10 | CursorDestroy = "cursor_destroy" 11 | 12 | HaulerPrefix = "hauler_" 13 | 14 | SpecialCardMarker = "card_marker" 15 | WarningMarker = "warning_marker" 16 | 17 | IndicatorPopulation = "indicator_population" 18 | IndicatorProduction = "indicator_production" 19 | IndicatorStorage = "indicator_storage" 20 | IndicatorInactiveSuffix = "_inactive" 21 | 22 | UiPanel = "ui_panel" 23 | UiPanelHover = "ui_panel_hover" 24 | UiPanelPressed = "ui_panel_pressed" 25 | 26 | Button = "button" 27 | ButtonHover = "button_hover" 28 | ButtonPressed = "button_pressed" 29 | ButtonDisabled = "button_disabled" 30 | ) 31 | -------------------------------------------------------------------------------- /game/sys/achievements.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mlange-42/arche/ecs" 7 | "github.com/mlange-42/arche/generic" 8 | "github.com/mlange-42/tiny-world/game/res" 9 | "github.com/mlange-42/tiny-world/game/res/achievements" 10 | "github.com/mlange-42/tiny-world/game/save" 11 | ) 12 | 13 | // Achievements system. 14 | type Achievements struct { 15 | PlayerFile string 16 | 17 | time generic.Resource[res.GameTick] 18 | update generic.Resource[res.UpdateInterval] 19 | editor generic.Resource[res.EditorMode] 20 | ui generic.Resource[res.UI] 21 | achievements generic.Resource[achievements.Achievements] 22 | } 23 | 24 | // Initialize the system 25 | func (s *Achievements) Initialize(world *ecs.World) { 26 | s.time = generic.NewResource[res.GameTick](world) 27 | s.update = generic.NewResource[res.UpdateInterval](world) 28 | s.editor = generic.NewResource[res.EditorMode](world) 29 | s.ui = generic.NewResource[res.UI](world) 30 | s.achievements = generic.NewResource[achievements.Achievements](world) 31 | } 32 | 33 | // Update the system 34 | func (s *Achievements) Update(world *ecs.World) { 35 | tick := s.time.Get().Tick 36 | 37 | if tick%s.update.Get().Interval != 0 { 38 | return 39 | } 40 | if s.editor.Get().IsEditor { 41 | return 42 | } 43 | 44 | achievements := s.achievements.Get() 45 | 46 | for i := range achievements.Achievements { 47 | ach := &achievements.Achievements[i] 48 | if ach.Completed { 49 | continue 50 | } 51 | achievements.Check(ach) 52 | if ach.Completed { 53 | achievements.Completed = append(achievements.Completed, ach.ID) 54 | save.SaveAchievements(s.PlayerFile, achievements.Completed) 55 | println(fmt.Sprintf("Achievement completed: %s", ach.Name)) 56 | s.ui.Get().SetStatusLabel(fmt.Sprintf(" \nAchievement completed!\n\"%s\"\n ", ach.Name)) 57 | } 58 | } 59 | } 60 | 61 | // Finalize the system 62 | func (s *Achievements) Finalize(world *ecs.World) {} 63 | -------------------------------------------------------------------------------- /game/sys/cheats.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/hajimehoshi/ebiten/v2" 5 | "github.com/hajimehoshi/ebiten/v2/inpututil" 6 | "github.com/mlange-42/arche/ecs" 7 | "github.com/mlange-42/arche/generic" 8 | "github.com/mlange-42/tiny-world/game/res" 9 | ) 10 | 11 | // Cheats system. 12 | type Cheats struct { 13 | rules generic.Resource[res.Rules] 14 | stock generic.Resource[res.Stock] 15 | ui generic.Resource[res.UI] 16 | editor generic.Resource[res.EditorMode] 17 | } 18 | 19 | // Initialize the system 20 | func (s *Cheats) Initialize(world *ecs.World) { 21 | s.rules = generic.NewResource[res.Rules](world) 22 | s.stock = generic.NewResource[res.Stock](world) 23 | s.ui = generic.NewResource[res.UI](world) 24 | s.editor = generic.NewResource[res.EditorMode](world) 25 | } 26 | 27 | // Update the system 28 | func (s *Cheats) Update(world *ecs.World) { 29 | if ebiten.IsKeyPressed(ebiten.KeyShift) && 30 | ebiten.IsKeyPressed(ebiten.KeyControl) && 31 | ebiten.IsKeyPressed(ebiten.KeyAlt) && 32 | inpututil.IsKeyJustPressed(ebiten.KeyR) { 33 | 34 | if s.editor.Get().IsEditor { 35 | println("cheats are not available in editor mode") 36 | return 37 | } 38 | 39 | stock := s.stock.Get() 40 | copy(stock.Res, stock.Cap) 41 | return 42 | } 43 | 44 | if ebiten.IsKeyPressed(ebiten.KeyShift) && 45 | ebiten.IsKeyPressed(ebiten.KeyControl) && 46 | ebiten.IsKeyPressed(ebiten.KeyAlt) && 47 | inpututil.IsKeyJustPressed(ebiten.KeyN) { 48 | 49 | if s.editor.Get().IsEditor { 50 | println("cheats are not available in editor mode") 51 | return 52 | } 53 | 54 | ui := s.ui.Get() 55 | ui.ReplaceAllButtons(s.rules.Get()) 56 | } 57 | } 58 | 59 | // Finalize the system 60 | func (s *Cheats) Finalize(world *ecs.World) {} 61 | -------------------------------------------------------------------------------- /game/sys/do_consumption.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/comp" 7 | "github.com/mlange-42/tiny-world/game/res" 8 | "github.com/mlange-42/tiny-world/game/resource" 9 | ) 10 | 11 | // DoConsumption system. 12 | type DoConsumption struct { 13 | speed generic.Resource[res.GameSpeed] 14 | time generic.Resource[res.GameTick] 15 | update generic.Resource[res.UpdateInterval] 16 | stock generic.Resource[res.Stock] 17 | editor generic.Resource[res.EditorMode] 18 | 19 | filter generic.Filter3[comp.UpdateTick, comp.Production, comp.Consumption] 20 | } 21 | 22 | // Initialize the system 23 | func (s *DoConsumption) Initialize(world *ecs.World) { 24 | s.speed = generic.NewResource[res.GameSpeed](world) 25 | s.time = generic.NewResource[res.GameTick](world) 26 | s.update = generic.NewResource[res.UpdateInterval](world) 27 | s.stock = generic.NewResource[res.Stock](world) 28 | s.editor = generic.NewResource[res.EditorMode](world) 29 | 30 | s.filter = *generic.NewFilter3[comp.UpdateTick, comp.Production, comp.Consumption]() 31 | } 32 | 33 | // Update the system 34 | func (s *DoConsumption) Update(world *ecs.World) { 35 | if s.speed.Get().Pause { 36 | return 37 | } 38 | isEditor := s.editor.Get().IsEditor 39 | 40 | stock := s.stock.Get() 41 | tick := s.time.Get().Tick 42 | update := s.update.Get() 43 | tickMod := tick % update.Interval 44 | 45 | query := s.filter.Query(world) 46 | for query.Next() { 47 | up, prod, cons := query.Get() 48 | 49 | if up.Tick != tickMod { 50 | continue 51 | } 52 | 53 | cons.IsSatisfied = true 54 | if isEditor { 55 | continue 56 | } 57 | 58 | for i, c := range cons.Amount { 59 | cons.Countdown[i] -= int16(c) 60 | if cons.Countdown[i] < 0 { 61 | if prod.Resource == resource.Resource(i) && prod.Stock > 0 { 62 | cons.Countdown[i] += int16(update.Countdown) 63 | prod.Stock-- 64 | } else if stock.Res[i] > 0 { 65 | cons.Countdown[i] += int16(update.Countdown) 66 | stock.Res[i]-- 67 | } else { 68 | cons.Countdown[i] = 0 69 | cons.IsSatisfied = false 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | // Finalize the system 77 | func (s *DoConsumption) Finalize(world *ecs.World) {} 78 | -------------------------------------------------------------------------------- /game/sys/do_production.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/comp" 7 | "github.com/mlange-42/tiny-world/game/res" 8 | "github.com/mlange-42/tiny-world/game/resource" 9 | "github.com/mlange-42/tiny-world/game/terr" 10 | ) 11 | 12 | // DoProduction system. 13 | type DoProduction struct { 14 | speed generic.Resource[res.GameSpeed] 15 | time generic.Resource[res.GameTick] 16 | update generic.Resource[res.UpdateInterval] 17 | stock generic.Resource[res.Stock] 18 | landUse generic.Resource[res.LandUse] 19 | editor generic.Resource[res.EditorMode] 20 | 21 | filter generic.Filter4[comp.Terrain, comp.Tile, comp.UpdateTick, comp.Production] 22 | markerBuilder generic.Map2[comp.Tile, comp.ProductionMarker] 23 | 24 | toCreate []markerEntry 25 | } 26 | 27 | // Initialize the system 28 | func (s *DoProduction) Initialize(world *ecs.World) { 29 | s.speed = generic.NewResource[res.GameSpeed](world) 30 | s.time = generic.NewResource[res.GameTick](world) 31 | s.update = generic.NewResource[res.UpdateInterval](world) 32 | s.stock = generic.NewResource[res.Stock](world) 33 | s.landUse = generic.NewResource[res.LandUse](world) 34 | s.editor = generic.NewResource[res.EditorMode](world) 35 | 36 | s.filter = *generic.NewFilter4[comp.Terrain, comp.Tile, comp.UpdateTick, comp.Production]() 37 | s.markerBuilder = generic.NewMap2[comp.Tile, comp.ProductionMarker](world) 38 | } 39 | 40 | // Update the system 41 | func (s *DoProduction) Update(world *ecs.World) { 42 | if s.speed.Get().Pause || s.editor.Get().IsEditor { 43 | return 44 | } 45 | 46 | tick := s.time.Get().Tick 47 | update := s.update.Get() 48 | tickMod := tick % update.Interval 49 | 50 | query := s.filter.Query(world) 51 | for query.Next() { 52 | ter, tile, up, pr := query.Get() 53 | 54 | if up.Tick != tickMod { 55 | continue 56 | } 57 | 58 | if pr.Stock >= terr.Properties[ter.Terrain].Storage[pr.Resource] { 59 | continue 60 | } 61 | 62 | pr.Countdown -= int(pr.Amount) 63 | if pr.Countdown < 0 { 64 | pr.Countdown += update.Countdown 65 | pr.Stock++ 66 | s.toCreate = append(s.toCreate, markerEntry{Tile: *tile, Resource: pr.Resource, Home: query.Entity()}) 67 | } 68 | } 69 | 70 | for _, entry := range s.toCreate { 71 | s.markerBuilder.NewWith( 72 | &entry.Tile, 73 | &comp.ProductionMarker{StartTick: tick, Resource: entry.Resource}, 74 | ) 75 | } 76 | s.toCreate = s.toCreate[:0] 77 | } 78 | 79 | // Finalize the system 80 | func (s *DoProduction) Finalize(world *ecs.World) {} 81 | 82 | type markerEntry struct { 83 | Tile comp.Tile 84 | Resource resource.Resource 85 | Home ecs.Entity 86 | } 87 | -------------------------------------------------------------------------------- /game/sys/game_controls.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "math" 5 | "slices" 6 | 7 | "github.com/hajimehoshi/ebiten/v2" 8 | "github.com/hajimehoshi/ebiten/v2/inpututil" 9 | "github.com/mlange-42/arche/ecs" 10 | "github.com/mlange-42/arche/generic" 11 | "github.com/mlange-42/tiny-world/game/res" 12 | ) 13 | 14 | // GameControls system. 15 | type GameControls struct { 16 | PauseKey ebiten.Key 17 | SlowerKey rune 18 | FasterKey rune 19 | FullscreenKey ebiten.Key 20 | 21 | speed generic.Resource[res.GameSpeed] 22 | update generic.Resource[res.UpdateInterval] 23 | prevSpeed int8 24 | 25 | inputChars []rune 26 | } 27 | 28 | // Initialize the system 29 | func (s *GameControls) Initialize(world *ecs.World) { 30 | s.speed = generic.NewResource[res.GameSpeed](world) 31 | s.update = generic.NewResource[res.UpdateInterval](world) 32 | 33 | speed := s.speed.Get() 34 | update := s.update.Get() 35 | 36 | ebiten.SetTPS(int(math.Pow(2, float64(speed.Speed)) * float64(update.Interval))) 37 | } 38 | 39 | // Update the system 40 | func (s *GameControls) Update(world *ecs.World) { 41 | speed := s.speed.Get() 42 | update := s.update.Get() 43 | 44 | if inpututil.IsKeyJustPressed(s.FullscreenKey) { 45 | ebiten.SetFullscreen(!ebiten.IsFullscreen()) 46 | } 47 | if inpututil.IsKeyJustPressed(s.PauseKey) { 48 | speed.Pause = !speed.Pause 49 | } 50 | 51 | s.inputChars = ebiten.AppendInputChars(s.inputChars) 52 | 53 | if speed.Speed > speed.MinSpeed && slices.Contains(s.inputChars, s.SlowerKey) { 54 | speed.Speed -= 1 55 | } 56 | if speed.Speed < speed.MaxSpeed && slices.Contains(s.inputChars, s.FasterKey) { 57 | speed.Speed += 1 58 | } 59 | 60 | s.inputChars = s.inputChars[:0] 61 | 62 | if s.prevSpeed != speed.Speed { 63 | ebiten.SetTPS(int(math.Pow(2, float64(speed.Speed)) * float64(update.Interval))) 64 | s.prevSpeed = speed.Speed 65 | } 66 | } 67 | 68 | // Finalize the system 69 | func (s *GameControls) Finalize(world *ecs.World) {} 70 | -------------------------------------------------------------------------------- /game/sys/init_terrain.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "image" 5 | 6 | "github.com/mlange-42/arche/ecs" 7 | "github.com/mlange-42/arche/generic" 8 | "github.com/mlange-42/tiny-world/game/comp" 9 | "github.com/mlange-42/tiny-world/game/res" 10 | "github.com/mlange-42/tiny-world/game/terr" 11 | ) 12 | 13 | // InitTerrain system. 14 | type InitTerrain struct { 15 | } 16 | 17 | // Initialize the system 18 | func (s *InitTerrain) Initialize(world *ecs.World) { 19 | rules := ecs.GetResource[res.Rules](world) 20 | fac := ecs.GetResource[res.EntityFactory](world) 21 | t := ecs.GetResource[res.Terrain](world) 22 | bounds := ecs.GetResource[res.WorldBounds](world) 23 | 24 | radiusMapper := generic.NewMap1[comp.BuildRadius](world) 25 | 26 | x, y := t.Width()/2, t.Height()/2 27 | bounds.Min = image.Pt(x-1, y-1) 28 | bounds.Max = image.Pt(x+1, y+1) 29 | 30 | fac.Set(world, x, y, terr.Default, 0, true) 31 | 32 | warehouse := fac.Set(world, x, y, terr.FirstBuilding, 0, true) 33 | radiusMapper.Assign(warehouse, &comp.BuildRadius{Radius: uint8(rules.InitialBuildRadius)}) 34 | 35 | fac.SetBuildable(x, y, rules.InitialBuildRadius, true) 36 | } 37 | 38 | // Update the system 39 | func (s *InitTerrain) Update(world *ecs.World) {} 40 | 41 | // Finalize the system 42 | func (s *InitTerrain) Finalize(world *ecs.World) {} 43 | -------------------------------------------------------------------------------- /game/sys/init_terrain_loaded.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/comp" 7 | "github.com/mlange-42/tiny-world/game/res" 8 | "github.com/mlange-42/tiny-world/game/terr" 9 | ) 10 | 11 | // InitTerrainLoaded system. 12 | type InitTerrainLoaded struct { 13 | } 14 | 15 | // Initialize the system 16 | func (s *InitTerrainLoaded) Initialize(world *ecs.World) { 17 | rules := ecs.GetResource[res.Rules](world) 18 | terrain := ecs.GetResource[res.Terrain](world) 19 | terrainE := ecs.GetResource[res.TerrainEntities](world) 20 | landUse := ecs.GetResource[res.LandUse](world) 21 | landUseE := ecs.GetResource[res.LandUseEntities](world) 22 | fac := ecs.GetResource[res.EntityFactory](world) 23 | 24 | filter := generic.NewFilter2[comp.Tile, comp.Terrain]() 25 | query := filter.Query(world) 26 | for query.Next() { 27 | tile, ter := query.Get() 28 | if terr.Properties[ter.Terrain].TerrainBits.Contains(terr.IsTerrain) { 29 | terrain.Set(tile.X, tile.Y, ter.Terrain) 30 | terrainE.Set(tile.X, tile.Y, query.Entity()) 31 | } else { 32 | landUse.Set(tile.X, tile.Y, ter.Terrain) 33 | landUseE.Set(tile.X, tile.Y, query.Entity()) 34 | } 35 | } 36 | 37 | x, y := terrain.Width()/2, terrain.Height()/2 38 | fac.SetBuildable(x, y, rules.InitialBuildRadius, true) 39 | 40 | radFilter := generic.NewFilter2[comp.Tile, comp.BuildRadius]() 41 | radQuery := radFilter.Query(world) 42 | for radQuery.Next() { 43 | tile, rad := radQuery.Get() 44 | fac.SetBuildable(tile.X, tile.Y, int(rad.Radius), true) 45 | } 46 | } 47 | 48 | // Update the system 49 | func (s *InitTerrainLoaded) Update(world *ecs.World) {} 50 | 51 | // Finalize the system 52 | func (s *InitTerrainLoaded) Finalize(world *ecs.World) {} 53 | -------------------------------------------------------------------------------- /game/sys/init_terrain_map.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "io/fs" 7 | "log" 8 | 9 | "github.com/mlange-42/arche/ecs" 10 | "github.com/mlange-42/arche/generic" 11 | "github.com/mlange-42/tiny-world/game/comp" 12 | "github.com/mlange-42/tiny-world/game/res" 13 | "github.com/mlange-42/tiny-world/game/save" 14 | "github.com/mlange-42/tiny-world/game/terr" 15 | ) 16 | 17 | // InitTerrainMap system. 18 | type InitTerrainMap struct { 19 | FS fs.FS 20 | MapFolder string 21 | Map save.MapLocation 22 | } 23 | 24 | // Initialize the system 25 | func (s *InitTerrainMap) Initialize(world *ecs.World) { 26 | rules := ecs.GetResource[res.Rules](world) 27 | terrain := ecs.GetResource[res.Terrain](world) 28 | bounds := ecs.GetResource[res.WorldBounds](world) 29 | fac := ecs.GetResource[res.EntityFactory](world) 30 | 31 | mapData, err := save.LoadMap(s.FS, s.MapFolder, s.Map) 32 | if err != nil { 33 | log.Fatal("error reading map file: ", err.Error()) 34 | } 35 | 36 | terrains := []terr.Terrain{} 37 | for _, rn := range mapData.Terrains { 38 | t, ok := terr.SymbolToTerrain[rn] 39 | if !ok { 40 | panic(fmt.Sprintf("unknown map symbol '%s'", string(rn))) 41 | } 42 | if t.LandUse != terr.Air { 43 | terrains = append(terrains, t.LandUse) 44 | } else { 45 | terrains = append(terrains, t.Terrain) 46 | } 47 | } 48 | rules.RandomTerrains = terrains 49 | rules.InitialRandomTerrains = mapData.InitialRandomTerrains 50 | 51 | xOff, yOff := terrain.Width()/2-mapData.Center.X, terrain.Height()/2-mapData.Center.Y 52 | 53 | x, y := terrain.Width()/2, terrain.Height()/2 54 | bounds.Min = image.Pt(x-1, y-1) 55 | bounds.Max = image.Pt(x+1, y+1) 56 | 57 | for y := 0; y < len(mapData.Data); y++ { 58 | line := mapData.Data[y] 59 | yy := y + yOff 60 | for x := 0; x < len(line); x++ { 61 | rn := line[x] 62 | ter, ok := terr.SymbolToTerrain[rn] 63 | if !ok { 64 | panic(fmt.Sprintf("unknown map symbol '%s'", string(rn))) 65 | } 66 | xx := x + xOff 67 | if ter.Terrain != terr.Air { 68 | fac.Set(world, xx, yy, ter.Terrain, 0, true) 69 | } 70 | if ter.LandUse != terr.Air { 71 | fac.Set(world, xx, yy, ter.LandUse, 0, true) 72 | } 73 | } 74 | } 75 | 76 | fac.SetBuildable(x, y, rules.InitialBuildRadius, true) 77 | 78 | radFilter := generic.NewFilter2[comp.Tile, comp.BuildRadius]() 79 | radQuery := radFilter.Query(world) 80 | for radQuery.Next() { 81 | tile, rad := radQuery.Get() 82 | fac.SetBuildable(tile.X, tile.Y, int(rad.Radius), true) 83 | } 84 | } 85 | 86 | // Update the system 87 | func (s *InitTerrainMap) Update(world *ecs.World) {} 88 | 89 | // Finalize the system 90 | func (s *InitTerrainMap) Finalize(world *ecs.World) {} 91 | -------------------------------------------------------------------------------- /game/sys/init_ui.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/tiny-world/game/res" 6 | ) 7 | 8 | // InitUI system. 9 | type InitUI struct { 10 | ui res.UI 11 | } 12 | 13 | // Initialize the system 14 | func (s *InitUI) Initialize(world *ecs.World) { 15 | s.ui = res.NewUI(world, 16 | ecs.GetResource[res.Selection](world), 17 | ecs.GetResource[res.Fonts](world), 18 | ecs.GetResource[res.Sprites](world), 19 | ecs.GetResource[res.RandomTerrains](world), 20 | ecs.GetResource[res.SaveEvent](world), 21 | ecs.GetResource[res.EditorMode](world)) 22 | 23 | ecs.AddResource(world, &s.ui) 24 | } 25 | 26 | // Update the system 27 | func (s *InitUI) Update(world *ecs.World) {} 28 | 29 | // Finalize the system 30 | func (s *InitUI) Finalize(world *ecs.World) {} 31 | -------------------------------------------------------------------------------- /game/sys/remove_markers.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/comp" 7 | "github.com/mlange-42/tiny-world/game/res" 8 | ) 9 | 10 | // RemoveMarkers system. 11 | type RemoveMarkers struct { 12 | MaxTime int64 13 | 14 | time generic.Resource[res.GameTick] 15 | filter generic.Filter1[comp.ProductionMarker] 16 | 17 | toRemove []ecs.Entity 18 | } 19 | 20 | // Initialize the system 21 | func (s *RemoveMarkers) Initialize(world *ecs.World) { 22 | s.time = generic.NewResource[res.GameTick](world) 23 | 24 | s.filter = *generic.NewFilter1[comp.ProductionMarker]() 25 | } 26 | 27 | // Update the system 28 | func (s *RemoveMarkers) Update(world *ecs.World) { 29 | tick := s.time.Get().Tick 30 | 31 | query := s.filter.Query(world) 32 | for query.Next() { 33 | mark := query.Get() 34 | if tick > mark.StartTick+s.MaxTime { 35 | s.toRemove = append(s.toRemove, query.Entity()) 36 | } 37 | } 38 | 39 | for _, e := range s.toRemove { 40 | world.RemoveEntity(e) 41 | } 42 | s.toRemove = s.toRemove[:0] 43 | } 44 | 45 | // Finalize the system 46 | func (s *RemoveMarkers) Finalize(world *ecs.World) {} 47 | -------------------------------------------------------------------------------- /game/sys/tick.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/res" 7 | ) 8 | 9 | // Tick system. 10 | type Tick struct { 11 | speed generic.Resource[res.GameSpeed] 12 | time generic.Resource[res.GameTick] 13 | } 14 | 15 | // Initialize the system 16 | func (s *Tick) Initialize(world *ecs.World) { 17 | s.speed = generic.NewResource[res.GameSpeed](world) 18 | s.time = generic.NewResource[res.GameTick](world) 19 | } 20 | 21 | // Update the system 22 | func (s *Tick) Update(world *ecs.World) { 23 | s.time.Get().RenderTick++ 24 | if !s.speed.Get().Pause { 25 | s.time.Get().Tick++ 26 | } 27 | } 28 | 29 | // Finalize the system 30 | func (s *Tick) Finalize(world *ecs.World) {} 31 | -------------------------------------------------------------------------------- /game/sys/update_population.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/comp" 7 | "github.com/mlange-42/tiny-world/game/math" 8 | "github.com/mlange-42/tiny-world/game/res" 9 | "github.com/mlange-42/tiny-world/game/terr" 10 | ) 11 | 12 | // UpdateProduction system. 13 | type UpdatePopulation struct { 14 | time generic.Resource[res.GameTick] 15 | speed generic.Resource[res.GameSpeed] 16 | update generic.Resource[res.UpdateInterval] 17 | terrain generic.Resource[res.Terrain] 18 | landUse generic.Resource[res.LandUse] 19 | 20 | filter generic.Filter3[comp.Tile, comp.UpdateTick, comp.PopulationSupport] 21 | } 22 | 23 | // Initialize the system 24 | func (s *UpdatePopulation) Initialize(world *ecs.World) { 25 | s.time = generic.NewResource[res.GameTick](world) 26 | s.speed = generic.NewResource[res.GameSpeed](world) 27 | s.update = generic.NewResource[res.UpdateInterval](world) 28 | s.terrain = generic.NewResource[res.Terrain](world) 29 | s.landUse = generic.NewResource[res.LandUse](world) 30 | 31 | s.filter = *generic.NewFilter3[comp.Tile, comp.UpdateTick, comp.PopulationSupport]() 32 | } 33 | 34 | // Update the system 35 | func (s *UpdatePopulation) Update(world *ecs.World) { 36 | if s.speed.Get().Pause { 37 | return 38 | } 39 | 40 | terrain := s.terrain.Get() 41 | landUse := s.landUse.Get() 42 | tick := s.time.Get().Tick 43 | interval := s.update.Get().Interval 44 | tickMod := tick % interval 45 | 46 | query := s.filter.Query(world) 47 | for query.Next() { 48 | tile, up, pop := query.Get() 49 | 50 | if up.Tick != tickMod { 51 | continue 52 | } 53 | pop.Pop = 0 54 | 55 | lu := landUse.Get(tile.X, tile.Y) 56 | 57 | supp := &terr.Properties[lu].PopulationSupport 58 | if supp.RequiredTerrain != terr.Air && 59 | terrain.CountNeighbors4(tile.X, tile.Y, supp.RequiredTerrain) == 0 && 60 | landUse.CountNeighbors4(tile.X, tile.Y, supp.RequiredTerrain) == 0 { 61 | pop.HasRequired = false 62 | continue 63 | } 64 | pop.HasRequired = true 65 | count := int(supp.BasePopulation) 66 | if supp.BonusTerrain != 0 { 67 | count += terrain.CountNeighborsMask8(tile.X, tile.Y, supp.BonusTerrain) + 68 | landUse.CountNeighborsMask8(tile.X, tile.Y, supp.BonusTerrain) 69 | } 70 | if supp.MalusTerrain != 0 { 71 | count -= terrain.CountNeighborsMask8(tile.X, tile.Y, supp.MalusTerrain) + 72 | landUse.CountNeighborsMask8(tile.X, tile.Y, supp.MalusTerrain) 73 | } 74 | pop.Pop = uint8(math.ClampInt(count, 0, int(supp.MaxPopulation))) 75 | } 76 | } 77 | 78 | // Finalize the system 79 | func (s *UpdatePopulation) Finalize(world *ecs.World) {} 80 | -------------------------------------------------------------------------------- /game/sys/update_production.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/comp" 7 | "github.com/mlange-42/tiny-world/game/math" 8 | "github.com/mlange-42/tiny-world/game/res" 9 | "github.com/mlange-42/tiny-world/game/terr" 10 | ) 11 | 12 | // UpdateProduction system. 13 | type UpdateProduction struct { 14 | time generic.Resource[res.GameTick] 15 | speed generic.Resource[res.GameSpeed] 16 | update generic.Resource[res.UpdateInterval] 17 | terrain generic.Resource[res.Terrain] 18 | landUse generic.Resource[res.LandUse] 19 | 20 | filter generic.Filter4[comp.Tile, comp.UpdateTick, comp.Production, comp.Consumption] 21 | } 22 | 23 | // Initialize the system 24 | func (s *UpdateProduction) Initialize(world *ecs.World) { 25 | s.time = generic.NewResource[res.GameTick](world) 26 | s.speed = generic.NewResource[res.GameSpeed](world) 27 | s.update = generic.NewResource[res.UpdateInterval](world) 28 | s.terrain = generic.NewResource[res.Terrain](world) 29 | s.landUse = generic.NewResource[res.LandUse](world) 30 | 31 | s.filter = *generic.NewFilter4[comp.Tile, comp.UpdateTick, comp.Production, comp.Consumption]().Optional(generic.T[comp.Consumption]()) 32 | } 33 | 34 | // Update the system 35 | func (s *UpdateProduction) Update(world *ecs.World) { 36 | if s.speed.Get().Pause { 37 | return 38 | } 39 | 40 | terrain := s.terrain.Get() 41 | landUse := s.landUse.Get() 42 | tick := s.time.Get().Tick 43 | interval := s.update.Get().Interval 44 | tickMod := tick % interval 45 | 46 | query := s.filter.Query(world) 47 | for query.Next() { 48 | tile, up, pr, cons := query.Get() 49 | 50 | if up.Tick != tickMod { 51 | continue 52 | } 53 | pr.Amount = 0 54 | 55 | if !cons.IsSatisfied { 56 | continue 57 | } 58 | 59 | lu := landUse.Get(tile.X, tile.Y) 60 | 61 | prod := &terr.Properties[lu].Production 62 | if prod.RequiredTerrain != terr.Air && 63 | terrain.CountNeighbors4(tile.X, tile.Y, prod.RequiredTerrain) == 0 && 64 | landUse.CountNeighbors4(tile.X, tile.Y, prod.RequiredTerrain) == 0 { 65 | pr.HasRequired = false 66 | continue 67 | } 68 | pr.HasRequired = true 69 | count := 0 70 | if prod.ProductionTerrain != 0 { 71 | count += terrain.CountNeighborsMask8(tile.X, tile.Y, prod.ProductionTerrain) + 72 | landUse.CountNeighborsMask8(tile.X, tile.Y, prod.ProductionTerrain) 73 | } 74 | pr.Amount = uint8(math.MinInt(count, int(prod.MaxProduction))) 75 | } 76 | } 77 | 78 | // Finalize the system 79 | func (s *UpdateProduction) Finalize(world *ecs.World) {} 80 | -------------------------------------------------------------------------------- /game/sys/update_ui.go: -------------------------------------------------------------------------------- 1 | package sys 2 | 3 | import ( 4 | "github.com/mlange-42/arche/ecs" 5 | "github.com/mlange-42/arche/generic" 6 | "github.com/mlange-42/tiny-world/game/res" 7 | ) 8 | 9 | // UpdateUI system. 10 | type UpdateUI struct { 11 | rules generic.Resource[res.Rules] 12 | ui generic.Resource[res.UI] 13 | } 14 | 15 | // Initialize the system 16 | func (s *UpdateUI) Initialize(world *ecs.World) { 17 | s.rules = generic.NewResource[res.Rules](world) 18 | s.ui = generic.NewResource[res.UI](world) 19 | 20 | rules := s.rules.Get() 21 | ui := s.ui.Get() 22 | ui.CreateRandomButtons(rules.RandomTerrainsCount) 23 | } 24 | 25 | // Update the system 26 | func (s *UpdateUI) Update(world *ecs.World) { 27 | ui := s.ui.Get() 28 | 29 | ui.Update() 30 | } 31 | 32 | // Finalize the system 33 | func (s *UpdateUI) Finalize(world *ecs.World) {} 34 | -------------------------------------------------------------------------------- /game/terr/directions.go: -------------------------------------------------------------------------------- 1 | package terr 2 | 3 | type Direction uint8 4 | 5 | const ( 6 | N Direction = iota 7 | E 8 | S 9 | W 10 | EndDirection 11 | ) 12 | 13 | func (d Direction) Deltas() (int, int) { 14 | dir := directionXY[d] 15 | return dir[0], dir[1] 16 | } 17 | 18 | func (d Direction) Opposite() Direction { 19 | return (d + 4) % EndDirection 20 | } 21 | 22 | type Directions uint8 23 | 24 | func NewDirections(dirs ...Direction) Directions { 25 | d := Directions(0) 26 | for _, dir := range dirs { 27 | d |= (1 << dir) 28 | } 29 | return d 30 | } 31 | 32 | func (d *Directions) Set(dir Direction) { 33 | *d |= (1 << dir) 34 | } 35 | 36 | func (d *Directions) Unset(dir Direction) { 37 | *d &= ^(1 << dir) 38 | } 39 | 40 | // Contains checks whether all the argument's bits are contained in this Subscription. 41 | func (d Directions) Contains(dir Direction) bool { 42 | bits := Directions(1 << dir) 43 | return (bits & d) == bits 44 | } 45 | 46 | var directionXY = [4][2]int{ 47 | {0, -1}, 48 | {1, 0}, 49 | {0, 1}, 50 | {-1, 0}, 51 | } 52 | -------------------------------------------------------------------------------- /game/util/format.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "image/color" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | func FormatDuration(dur time.Duration) string { 11 | hours := int(dur.Hours()) 12 | mins := int(dur.Minutes()) - 60*hours 13 | return fmt.Sprintf("%d:%02d", hours, mins) 14 | } 15 | 16 | func Capitalize(s string) string { 17 | if len(s) == 0 { 18 | return "" 19 | } 20 | runes := []rune(s) 21 | runes[0] = []rune(strings.ToUpper(string(runes[0])))[0] 22 | return string(runes) 23 | } 24 | 25 | func ColorToBB(color color.RGBA) string { 26 | return fmt.Sprintf("%02x%02x%02x", color.R, color.G, color.B) 27 | } 28 | -------------------------------------------------------------------------------- /game/util/pool.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | // IntValue covers all integer types supported by [IntPool]. 4 | type IntValue interface { 5 | int | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64 6 | } 7 | 8 | // IntPool is an implementation using implicit linked lists. 9 | // Implements https://skypjack.github.io/2019-05-06-ecs-baf-part-3/ 10 | type IntPool[T IntValue] struct { 11 | pool []T 12 | next T 13 | available uint32 14 | capacityIncrement uint32 15 | } 16 | 17 | // NewIntPool creates a new, initialized Entity pool. 18 | func NewIntPool[T IntValue](capacityIncrement uint32) IntPool[T] { 19 | return IntPool[T]{ 20 | pool: make([]T, 0, capacityIncrement), 21 | next: 0, 22 | available: 0, 23 | capacityIncrement: capacityIncrement, 24 | } 25 | } 26 | 27 | // Get returns a fresh or recycled entity. 28 | func (p *IntPool[T]) Get() T { 29 | if p.available == 0 { 30 | return p.getNew() 31 | } 32 | curr := p.next 33 | p.next, p.pool[p.next] = p.pool[p.next], p.next 34 | p.available-- 35 | return p.pool[curr] 36 | } 37 | 38 | // Allocates and returns a new entity. For internal use. 39 | func (p *IntPool[T]) getNew() T { 40 | e := T(len(p.pool)) 41 | if len(p.pool) == cap(p.pool) { 42 | old := p.pool 43 | p.pool = make([]T, len(p.pool), len(p.pool)+int(p.capacityIncrement)) 44 | copy(p.pool, old) 45 | } 46 | p.pool = append(p.pool, e) 47 | return e 48 | } 49 | 50 | // Recycle hands an entity back for recycling. 51 | func (p *IntPool[T]) Recycle(e T) { 52 | p.next, p.pool[e] = e, p.next 53 | p.available++ 54 | } 55 | 56 | // Reset recycles all entities. Does NOT free the reserved memory. 57 | func (p *IntPool[T]) Reset() { 58 | p.pool = p.pool[:0] 59 | p.next = 0 60 | p.available = 0 61 | } 62 | -------------------------------------------------------------------------------- /game/util/rect.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "image" 4 | 5 | func Clamp(r image.Rectangle, p image.Point) image.Point { 6 | if p.X < r.Min.X { 7 | p.X = r.Min.X 8 | } 9 | if p.Y < r.Min.Y { 10 | p.Y = r.Min.Y 11 | } 12 | if p.X > r.Max.X { 13 | p.X = r.Max.X 14 | } 15 | if p.Y > r.Max.Y { 16 | p.Y = r.Max.Y 17 | } 18 | return p 19 | } 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mlange-42/tiny-world 2 | 3 | go 1.22 4 | 5 | toolchain go1.22.0 6 | 7 | require ( 8 | github.com/ebitenui/ebitenui v0.5.6-0.20240306013559-bea9affc3db0 9 | github.com/hajimehoshi/ebiten/v2 v2.6.6 10 | github.com/mlange-42/arche v0.11.0 11 | github.com/mlange-42/arche-model v0.7.0 12 | github.com/mlange-42/arche-serde v0.2.0 13 | github.com/spf13/cobra v1.8.0 14 | golang.org/x/image v0.15.0 15 | ) 16 | 17 | require ( 18 | github.com/ebitengine/purego v0.6.1 // indirect 19 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 20 | github.com/jezek/xgb v1.1.1 // indirect 21 | github.com/spf13/pflag v1.0.5 // indirect 22 | golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect 23 | golang.org/x/exp/shiny v0.0.0-20240222234643-814bf88cf225 // indirect 24 | golang.org/x/mobile v0.0.0-20240213143359-d1f7d3436075 // indirect 25 | golang.org/x/sync v0.6.0 // indirect 26 | golang.org/x/sys v0.18.0 // indirect 27 | golang.org/x/text v0.14.0 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/mlange-42/tiny-world/game" 4 | 5 | func main() { 6 | game.Run(GameData) 7 | } 8 | --------------------------------------------------------------------------------