├── .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 |

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 |
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 |
--------------------------------------------------------------------------------