mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 00:01:34 +11:00
add the dungeon keeper's lament
This commit is contained in:
parent
a7f9fdf011
commit
0fac43746f
14
examples/the-dungeon-keepers-lament/.cargo/config.toml
Normal file
14
examples/the-dungeon-keepers-lament/.cargo/config.toml
Normal file
|
@ -0,0 +1,14 @@
|
|||
[unstable]
|
||||
build-std = ["core", "alloc"]
|
||||
build-std-features = ["compiler-builtins-mem"]
|
||||
|
||||
[build]
|
||||
target = "thumbv4t-none-eabi"
|
||||
|
||||
[target.thumbv4t-none-eabi]
|
||||
rustflags = ["-Clink-arg=-Tgba.ld", "-Ctarget-cpu=arm7tdmi"]
|
||||
runner = "mgba-qt"
|
||||
|
||||
[target.armv4t-none-eabi]
|
||||
rustflags = ["-Clink-arg=-Tgba.ld", "-Ctarget-cpu=arm7tdmi"]
|
||||
runner = "mgba-qt"
|
479
examples/the-dungeon-keepers-lament/Cargo.lock
generated
Normal file
479
examples/the-dungeon-keepers-lament/Cargo.lock
generated
Normal file
|
@ -0,0 +1,479 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||
|
||||
[[package]]
|
||||
name = "agb"
|
||||
version = "0.16.0"
|
||||
dependencies = [
|
||||
"agb_fixnum",
|
||||
"agb_hashmap",
|
||||
"agb_image_converter",
|
||||
"agb_macros",
|
||||
"agb_sound_converter",
|
||||
"bare-metal",
|
||||
"bilge",
|
||||
"bitflags 2.3.3",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agb_fixnum"
|
||||
version = "0.16.0"
|
||||
dependencies = [
|
||||
"agb_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agb_hashmap"
|
||||
version = "0.16.0"
|
||||
dependencies = [
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agb_image_converter"
|
||||
version = "0.16.0"
|
||||
dependencies = [
|
||||
"asefile",
|
||||
"fontdue",
|
||||
"image",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agb_macros"
|
||||
version = "0.16.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agb_sound_converter"
|
||||
version = "0.16.0"
|
||||
dependencies = [
|
||||
"hound",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary-int"
|
||||
version = "1.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe8e2a586ecd6eb29477a0c25b19742acca4fa5e39c92e127656616810c20579"
|
||||
|
||||
[[package]]
|
||||
name = "asefile"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6277c3125ad5045ff11474a50dd43b31baffdd32c17e580137f176b8025fde71"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"flate2",
|
||||
"image",
|
||||
"log",
|
||||
"nohash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
|
||||
|
||||
[[package]]
|
||||
name = "bilge"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79ce1664066c385d913b974a9f59746a78b7e550e9ffb7984eda322ab8bf5e08"
|
||||
dependencies = [
|
||||
"arbitrary-int",
|
||||
"bilge-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bilge-impl"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60fd0a3dc3001795b19260220070e6e8cbb3d8013351f382cc38533a41ca6e27"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fontdue"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0793f5137567643cf65ea42043a538804ff0fbf288649e2141442b602d81f9bc"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hound"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.23.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"color_quant",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"crc32fast",
|
||||
"libflate_lz77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libflate_lz77"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf"
|
||||
dependencies = [
|
||||
"rle-decode-fast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nohash"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0f889fb66f7acdf83442c35775764b51fed3c606ab9cee51500dbde2cf528ca"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.16.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
"deflate",
|
||||
"miniz_oxide 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rle-decode-fast"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "the-dungeon-keepers-lament"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"agb",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"slotmap",
|
||||
"tiled",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiled"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "181e2402be287d74e951a8e81c8798d0737cc94b1a089237bb3b838be76c6b5b"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"libflate",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336"
|
25
examples/the-dungeon-keepers-lament/Cargo.toml
Normal file
25
examples/the-dungeon-keepers-lament/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "the-dungeon-keepers-lament"
|
||||
version = "0.1.0"
|
||||
authors = [""]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
agb = { version = "0.16.0", path = "../../agb" }
|
||||
slotmap = { version = "1", default-features = false }
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
debug = true
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = "fat"
|
||||
debug = true
|
||||
|
||||
[build-dependencies]
|
||||
tiled = { version = "0.11", default-features = false }
|
||||
quote = "1"
|
||||
proc-macro2 = "1"
|
350
examples/the-dungeon-keepers-lament/build.rs
Normal file
350
examples/the-dungeon-keepers-lament/build.rs
Normal file
|
@ -0,0 +1,350 @@
|
|||
use quote::{quote, TokenStreamExt};
|
||||
use std::{
|
||||
env,
|
||||
fs::File,
|
||||
io::{BufWriter, Write},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
const LEVEL_NAMES: &[&str] = &[
|
||||
"level1",
|
||||
"level2",
|
||||
"level3",
|
||||
"level4",
|
||||
"level5",
|
||||
"level6",
|
||||
"level_switch",
|
||||
"level_spikes",
|
||||
"level_spikes2",
|
||||
"squid_force_button",
|
||||
"level_squid_intro",
|
||||
"level_squid2",
|
||||
"level_squid1",
|
||||
"level_squid_item",
|
||||
"level_squid_button",
|
||||
"level_squid_drop",
|
||||
"level_spikes3",
|
||||
"level_around",
|
||||
"level_squidprogramming",
|
||||
];
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").expect("OUT_DIR environment variable must be specified");
|
||||
|
||||
let mut tile_loader = tiled::Loader::new();
|
||||
|
||||
let ui_map = load_tmx(&mut tile_loader, "maps/UI.tmx");
|
||||
let ui_tiles = export_tiles(&ui_map, quote!(ui));
|
||||
|
||||
let levels = LEVEL_NAMES
|
||||
.iter()
|
||||
.map(|level| load_level(&mut tile_loader, &format!("maps/levels/{level}.tmx")))
|
||||
.collect::<Vec<_>>();
|
||||
let levels_tiles = levels.iter().map(|level| &level.0);
|
||||
let levels_data = levels.iter().map(|level| &level.1);
|
||||
|
||||
let tilemaps_output = quote! {
|
||||
use agb::display::tiled::TileSetting;
|
||||
|
||||
pub const UI_BACKGROUND_MAP: &[TileSetting] = #ui_tiles;
|
||||
pub const LEVELS_MAP: &[&[TileSetting]] = &[#(#levels_tiles),*];
|
||||
};
|
||||
|
||||
let levels_output = quote! {
|
||||
pub const LEVELS: &[Level] = &[#(#levels_data),*];
|
||||
};
|
||||
|
||||
{
|
||||
let tilemaps_output_file = File::create(format!("{out_dir}/tilemaps.rs"))
|
||||
.expect("Failed to open tilemaps.rs for writing");
|
||||
let mut tilemaps_writer = BufWriter::new(tilemaps_output_file);
|
||||
write!(&mut tilemaps_writer, "{tilemaps_output}").unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
let levels_output_file = File::create(format!("{out_dir}/levels.rs"))
|
||||
.expect("Failed to open levels.rs for writing");
|
||||
let mut levels_output_writer = BufWriter::new(levels_output_file);
|
||||
|
||||
write!(&mut levels_output_writer, "{levels_output}").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn load_level(loader: &mut tiled::Loader, filename: &str) -> (TokenStream, Level) {
|
||||
let level_map = load_tmx(loader, filename);
|
||||
let tiles = export_tiles(&level_map, quote!(level));
|
||||
let data = export_level(&level_map);
|
||||
|
||||
(tiles, data)
|
||||
}
|
||||
|
||||
fn load_tmx(loader: &mut tiled::Loader, filename: &str) -> tiled::Map {
|
||||
println!("cargo:rerun-if-changed={filename}");
|
||||
loader.load_tmx_map(filename).expect("failed to load map")
|
||||
}
|
||||
|
||||
enum Entity {
|
||||
Sword,
|
||||
Slime,
|
||||
Hero,
|
||||
Stairs,
|
||||
Door,
|
||||
Key,
|
||||
Switch,
|
||||
SwitchPressed,
|
||||
SwitchedOpenDoor,
|
||||
SwitchedClosedDoor,
|
||||
SpikesUp,
|
||||
SpikesDown,
|
||||
SquidUp,
|
||||
SquidDown,
|
||||
}
|
||||
|
||||
impl FromStr for Entity {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
use Entity::*;
|
||||
|
||||
Ok(match s {
|
||||
"SWORD" => Sword,
|
||||
"SLIME" => Slime,
|
||||
"HERO" => Hero,
|
||||
"STAIRS" => Stairs,
|
||||
"DOOR" => Door,
|
||||
"KEY" => Key,
|
||||
"SWITCH" => Switch,
|
||||
"SWITCH_PRESSED" => SwitchPressed,
|
||||
"DOOR_SWITCHED" => SwitchedClosedDoor,
|
||||
"DOOR_SWITCHED_OPEN" => SwitchedOpenDoor,
|
||||
"SPIKES" => SpikesUp,
|
||||
"SPIKES_DOWN" => SpikesDown,
|
||||
"SQUID_UP" => SquidUp,
|
||||
"SQUID_DOWN" => SquidDown,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for Entity {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
use Entity::*;
|
||||
|
||||
tokens.append_all(match self {
|
||||
Sword => quote!(Item::Sword),
|
||||
Slime => quote!(Item::Slime),
|
||||
Hero => quote!(Item::Hero),
|
||||
Stairs => quote!(Item::Stairs),
|
||||
Door => quote!(Item::Door),
|
||||
Key => quote!(Item::Key),
|
||||
Switch => quote!(Item::Switch),
|
||||
SwitchPressed => quote!(Item::SwitchPressed),
|
||||
SwitchedOpenDoor => quote!(Item::SwitchedOpenDoor),
|
||||
SwitchedClosedDoor => quote!(Item::SwitchedClosedDoor),
|
||||
SpikesUp => quote!(Item::SpikesUp),
|
||||
SpikesDown => quote!(Item::SpikesDown),
|
||||
SquidUp => quote!(Item::SquidUp),
|
||||
SquidDown => quote!(Item::SquidDown),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl TryFrom<char> for Direction {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(c: char) -> Result<Self, Self::Error> {
|
||||
use Direction::*;
|
||||
|
||||
Ok(match c {
|
||||
'U' => Up,
|
||||
'D' => Down,
|
||||
'L' => Left,
|
||||
'R' => Right,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for Direction {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
use Direction::*;
|
||||
|
||||
tokens.append_all(match self {
|
||||
Up => quote!(Direction::Up),
|
||||
Down => quote!(Direction::Down),
|
||||
Left => quote!(Direction::Left),
|
||||
Right => quote!(Direction::Right),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct EntityWithPosition(Entity, (i32, i32));
|
||||
|
||||
impl quote::ToTokens for EntityWithPosition {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let pos_x = self.1 .0;
|
||||
let pos_y = self.1 .1;
|
||||
let location = quote!(Vector2D::new(#pos_x, #pos_y));
|
||||
let item = &self.0;
|
||||
|
||||
tokens.append_all(quote!(Entity(#item, #location)))
|
||||
}
|
||||
}
|
||||
|
||||
struct Level {
|
||||
starting_items: Vec<Entity>,
|
||||
fixed_positions: Vec<EntityWithPosition>,
|
||||
directions: Vec<Direction>,
|
||||
wall_bitmap: Vec<u8>,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl quote::ToTokens for Level {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let wall_bitmap = &self.wall_bitmap;
|
||||
let fixed_positions = &self.fixed_positions;
|
||||
let directions = &self.directions;
|
||||
let starting_items = &self.starting_items;
|
||||
let name = &self.name;
|
||||
|
||||
tokens.append_all(quote! {
|
||||
Level::new(
|
||||
Map::new(11, 10, &[#(#wall_bitmap),*]),
|
||||
&[#(#fixed_positions),*],
|
||||
&[#(#directions),*],
|
||||
&[#(#starting_items),*],
|
||||
#name,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn export_level(map: &tiled::Map) -> Level {
|
||||
let objects = map.get_layer(1).unwrap().as_object_layer().unwrap();
|
||||
|
||||
let fixed_positions = objects.objects().map(|obj| {
|
||||
let entity: Entity = obj
|
||||
.name
|
||||
.parse()
|
||||
.unwrap_or_else(|_| panic!("unknown object type {}", obj.name));
|
||||
|
||||
let x = (obj.x / 16.0) as i32;
|
||||
let y = (obj.y / 16.0) as i32;
|
||||
|
||||
EntityWithPosition(entity, (x, y))
|
||||
});
|
||||
|
||||
let Some(tiled::PropertyValue::StringValue(starting_items)) = map.properties.get("ITEMS")
|
||||
else {
|
||||
panic!("Starting items must be a string")
|
||||
};
|
||||
|
||||
let Some(tiled::PropertyValue::StringValue(level_name)) = map.properties.get("NAME") else {
|
||||
panic!("Level name must be a string")
|
||||
};
|
||||
|
||||
let starting_items = starting_items.split(',').map(|starting_item| {
|
||||
starting_item
|
||||
.parse()
|
||||
.unwrap_or_else(|_| panic!("unknown object type {}", starting_item))
|
||||
});
|
||||
|
||||
let Some(tiled::PropertyValue::StringValue(directions)) = map.properties.get("DIRECTIONS")
|
||||
else {
|
||||
panic!("Starting items must be a string")
|
||||
};
|
||||
|
||||
let directions = directions.chars().map(|starting_item| {
|
||||
starting_item
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| panic!("unknown object type {}", starting_item))
|
||||
});
|
||||
|
||||
let Some(tiled::TileLayer::Finite(tiles)) = map.get_layer(0).unwrap().as_tile_layer() else {
|
||||
panic!("Not a finite layer")
|
||||
};
|
||||
|
||||
let are_walls = (0..10 * 11).map(|id| {
|
||||
let tile_x = id % 11;
|
||||
let tile_y = id / 11;
|
||||
|
||||
let is_wall = tiles
|
||||
.get_tile(tile_x * 2, tile_y * 2)
|
||||
.map(|tile| {
|
||||
let tileset = tile.get_tileset();
|
||||
let tile_data = &tileset.get_tile(tile.id()).unwrap();
|
||||
tile_data
|
||||
.user_type
|
||||
.as_ref()
|
||||
.map(|user_type| user_type == "WALL")
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.unwrap_or(true);
|
||||
|
||||
is_wall
|
||||
});
|
||||
|
||||
Level {
|
||||
starting_items: starting_items.collect(),
|
||||
fixed_positions: fixed_positions.collect(),
|
||||
directions: directions.collect(),
|
||||
wall_bitmap: bool_to_bit(&are_walls.collect::<Vec<_>>()),
|
||||
name: level_name.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn export_tiles(map: &tiled::Map, background: TokenStream) -> TokenStream {
|
||||
let map_tiles = map.get_layer(0).unwrap().as_tile_layer().unwrap();
|
||||
|
||||
let width = map_tiles.width().unwrap();
|
||||
let height = map_tiles.height().unwrap();
|
||||
|
||||
let map_tiles = (0..(height * width)).map(|pos| {
|
||||
let x = pos % width;
|
||||
let y = pos / width;
|
||||
|
||||
let tile = map_tiles.get_tile(x as i32, y as i32);
|
||||
|
||||
match tile {
|
||||
Some(tile) => {
|
||||
let tile_id = tile.id() as u16;
|
||||
let vflip = tile.flip_h;
|
||||
let hflip = tile.flip_v;
|
||||
let palette_id =
|
||||
quote! { backgrounds::#background.palette_assignments[#tile_id as usize] };
|
||||
quote! { TileSetting::new(#tile_id, #vflip, #hflip, #palette_id) }
|
||||
}
|
||||
None => {
|
||||
quote! { TileSetting::new(1023, false, false, 0) }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {&[#(#map_tiles),*]}
|
||||
}
|
||||
|
||||
fn bool_to_bit(bools: &[bool]) -> Vec<u8> {
|
||||
bools
|
||||
.chunks(8)
|
||||
.map(|x| {
|
||||
x.iter()
|
||||
.enumerate()
|
||||
.fold(0u8, |bits, (idx, &bit)| bits | ((bit as u8) << idx))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_bool_to_bit() {
|
||||
let bools = [true, false, false, false, true, true, true, true];
|
||||
assert_eq!(bool_to_bit(&bools), [0b11110001]);
|
||||
}
|
BIN
examples/the-dungeon-keepers-lament/fnt/yoster.ttf
Normal file
BIN
examples/the-dungeon-keepers-lament/fnt/yoster.ttf
Normal file
Binary file not shown.
115
examples/the-dungeon-keepers-lament/gba.ld
Normal file
115
examples/the-dungeon-keepers-lament/gba.ld
Normal file
|
@ -0,0 +1,115 @@
|
|||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
rom (rx) : ORIGIN = 0x08000000, LENGTH = 32M
|
||||
}
|
||||
|
||||
__text_start = ORIGIN(rom);
|
||||
|
||||
SECTIONS {
|
||||
. = __text_start;
|
||||
|
||||
|
||||
.text : {
|
||||
KEEP(*(.crt0));
|
||||
*(.crt0 .crt0*);
|
||||
*(.text .text*);
|
||||
. = ALIGN(4);
|
||||
} > rom
|
||||
__text_end = .;
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*);
|
||||
. = ALIGN(4);
|
||||
} > rom
|
||||
|
||||
__iwram_rom_start = .;
|
||||
.iwram : {
|
||||
__iwram_data_start = ABSOLUTE(.);
|
||||
|
||||
*(.iwram .iwram.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
*(.text_iwram .text_iwram.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
__iwram_data_end = ABSOLUTE(.);
|
||||
} > iwram AT>rom
|
||||
|
||||
. = __iwram_rom_start + (__iwram_data_end - __iwram_data_start);
|
||||
|
||||
__ewram_rom_start = .;
|
||||
.ewram : {
|
||||
__ewram_data_start = ABSOLUTE(.);
|
||||
|
||||
*(.ewram .ewram.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
*(.data .data.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
__ewram_data_end = ABSOLUTE(.);
|
||||
} > ewram AT>rom
|
||||
|
||||
.bss : {
|
||||
*(.bss .bss.*);
|
||||
. = ALIGN(4);
|
||||
__iwram_end = ABSOLUTE(.);
|
||||
} > iwram
|
||||
|
||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||
__iwram_rom_length_halfwords = (__iwram_rom_length_bytes + 1) / 2;
|
||||
|
||||
__ewram_rom_length_bytes = __ewram_data_end - __ewram_data_start;
|
||||
__ewram_rom_length_halfwords = (__ewram_rom_length_bytes + 1) / 2;
|
||||
|
||||
.shstrtab : {
|
||||
*(.shstrtab)
|
||||
}
|
||||
|
||||
/* debugging sections */
|
||||
/* Stabs */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
|
||||
/* discard anything not already mentioned */
|
||||
/DISCARD/ : { *(*) }
|
||||
}
|
113
examples/the-dungeon-keepers-lament/gba_mb.ld
Normal file
113
examples/the-dungeon-keepers-lament/gba_mb.ld
Normal file
|
@ -0,0 +1,113 @@
|
|||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(__start)
|
||||
EXTERN(__RUST_INTERRUPT_HANDLER)
|
||||
|
||||
EXTERN(__agbabi_memset)
|
||||
EXTERN(__agbabi_memcpy)
|
||||
|
||||
MEMORY {
|
||||
ewram (w!x) : ORIGIN = 0x02000000, LENGTH = 256K
|
||||
iwram (w!x) : ORIGIN = 0x03000000, LENGTH = 32K
|
||||
}
|
||||
|
||||
__text_start = ORIGIN(ewram);
|
||||
|
||||
SECTIONS {
|
||||
. = __text_start;
|
||||
|
||||
.text : {
|
||||
KEEP(*(.crt0));
|
||||
*(.crt0 .crt0*);
|
||||
*(.text .text*);
|
||||
. = ALIGN(4);
|
||||
} > rom
|
||||
__text_end = .;
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*);
|
||||
. = ALIGN(4);
|
||||
} > ewram
|
||||
|
||||
__iwram_rom_start = .;
|
||||
.iwram : {
|
||||
__iwram_data_start = ABSOLUTE(.);
|
||||
|
||||
*(.iwram .iwram.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
*(.text_iwram .text_iwram.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
__iwram_data_end = ABSOLUTE(.);
|
||||
} > iwram AT>ewram
|
||||
|
||||
. = __iwram_rom_start + (__iwram_data_end - __iwram_data_start);
|
||||
|
||||
__ewram_rom_start = .;
|
||||
.ewram : {
|
||||
__ewram_data_start = ABSOLUTE(.);
|
||||
|
||||
*(.ewram .ewram.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
*(.data .data.*);
|
||||
. = ALIGN(4);
|
||||
|
||||
__ewram_data_end = ABSOLUTE(.);
|
||||
} > ewram AT>ewram
|
||||
|
||||
.bss : {
|
||||
*(.bss .bss.*);
|
||||
. = ALIGN(4);
|
||||
__iwram_end = ABSOLUTE(.);
|
||||
} > iwram
|
||||
|
||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||
__iwram_rom_length_halfwords = (__iwram_rom_length_bytes + 1) / 2;
|
||||
|
||||
__ewram_rom_length_bytes = __ewram_data_end - __ewram_data_start;
|
||||
__ewram_rom_length_halfwords = (__ewram_rom_length_bytes + 1) / 2;
|
||||
|
||||
.shstrtab : {
|
||||
*(.shstrtab)
|
||||
}
|
||||
|
||||
/* debugging sections */
|
||||
/* Stabs */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
|
||||
/* discard anything not already mentioned */
|
||||
/DISCARD/ : { *(*) }
|
||||
}
|
BIN
examples/the-dungeon-keepers-lament/gfx/concept.aseprite
Normal file
BIN
examples/the-dungeon-keepers-lament/gfx/concept.aseprite
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/gfx/countdown.aseprite
Normal file
BIN
examples/the-dungeon-keepers-lament/gfx/countdown.aseprite
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/gfx/ending_page.aseprite
Normal file
BIN
examples/the-dungeon-keepers-lament/gfx/ending_page.aseprite
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/gfx/level.aseprite
Normal file
BIN
examples/the-dungeon-keepers-lament/gfx/level.aseprite
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/gfx/sprites16x16.aseprite
Normal file
BIN
examples/the-dungeon-keepers-lament/gfx/sprites16x16.aseprite
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/gfx/sprites8x8.aseprite
Normal file
BIN
examples/the-dungeon-keepers-lament/gfx/sprites8x8.aseprite
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/gfx/ui_tiles.aseprite
Normal file
BIN
examples/the-dungeon-keepers-lament/gfx/ui_tiles.aseprite
Normal file
Binary file not shown.
28
examples/the-dungeon-keepers-lament/maps/UI.tmx
Normal file
28
examples/the-dungeon-keepers-lament/maps/UI.tmx
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||
<tileset firstgid="1" source="UI.tsx"/>
|
||||
<layer id="1" name="UI" width="30" height="20">
|
||||
<data encoding="csv">
|
||||
1,97,98,99,100,101,102,75,3,4,5,6,3,4,5,6,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
||||
1073741928,112,113,114,115,116,117,1073741927,0,0,0,0,0,0,0,0,0,0,0,0,0,22,23,24,25,26,27,28,29,30,
|
||||
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,21,21,21,21,21,21,21,20,
|
||||
18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,21,21,21,21,21,21,21,20,
|
||||
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,21,21,21,21,21,21,21,19,
|
||||
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,21,21,21,21,21,21,21,19,
|
||||
16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,21,21,21,21,21,21,21,20,
|
||||
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,21,21,21,21,21,21,21,20,
|
||||
18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,21,21,21,21,21,21,21,19,
|
||||
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,38,39,42,43,42,43,44,45,
|
||||
16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,53,54,55,56,57,58,59,60,
|
||||
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,21,21,21,21,21,21,21,20,
|
||||
18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1073741865,21,21,21,21,21,21,21,20,
|
||||
18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,21,21,21,21,21,21,21,19,
|
||||
16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1073741846,21,21,21,21,21,21,21,19,
|
||||
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,21,21,21,21,21,21,21,20,
|
||||
18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,21,21,21,21,21,21,21,20,
|
||||
16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,21,21,21,21,21,21,21,20,
|
||||
104,61,62,63,64,65,66,67,68,69,70,91,92,93,94,95,96,70,103,0,0,41,21,21,21,21,21,21,21,20,
|
||||
31,76,77,78,79,80,81,82,83,84,85,106,107,108,109,110,111,85,118,35,36,46,47,48,49,47,48,49,50,51
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
4
examples/the-dungeon-keepers-lament/maps/UI.tsx
Normal file
4
examples/the-dungeon-keepers-lament/maps/UI.tsx
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.10" tiledversion="1.10.1" name="UI" tilewidth="8" tileheight="8" tilecount="60" columns="15">
|
||||
<image source="ui_tiles.png" width="120" height="32"/>
|
||||
</tileset>
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"automappingRulesFile": "",
|
||||
"commands": [
|
||||
],
|
||||
"compatibilityVersion": 1100,
|
||||
"extensionsPath": "extensions",
|
||||
"folders": [
|
||||
"."
|
||||
],
|
||||
"propertyTypes": [
|
||||
]
|
||||
}
|
BIN
examples/the-dungeon-keepers-lament/maps/level.png
Normal file
BIN
examples/the-dungeon-keepers-lament/maps/level.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
176
examples/the-dungeon-keepers-lament/maps/level.tsx
Normal file
176
examples/the-dungeon-keepers-lament/maps/level.tsx
Normal file
|
@ -0,0 +1,176 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.10" tiledversion="1.10.1" name="level" tilewidth="8" tileheight="8" tilecount="324" columns="18">
|
||||
<image source="level.png" width="144" height="144"/>
|
||||
<tile id="0" type="WALL"/>
|
||||
<tile id="1" type="WALL"/>
|
||||
<tile id="2" type="WALL"/>
|
||||
<tile id="3" type="WALL"/>
|
||||
<tile id="4" type="WALL"/>
|
||||
<tile id="5" type="WALL"/>
|
||||
<tile id="6" type="WALL"/>
|
||||
<tile id="7" type="WALL"/>
|
||||
<tile id="8" type="WALL"/>
|
||||
<tile id="9" type="WALL"/>
|
||||
<tile id="10" type="WALL"/>
|
||||
<tile id="11" type="WALL"/>
|
||||
<tile id="12" type="WALL"/>
|
||||
<tile id="13" type="WALL"/>
|
||||
<tile id="14" type="WALL"/>
|
||||
<tile id="15" type="WALL"/>
|
||||
<tile id="16" type="WALL"/>
|
||||
<tile id="17" type="WALL"/>
|
||||
<tile id="18" type="WALL"/>
|
||||
<tile id="19" type="WALL"/>
|
||||
<tile id="20" type="WALL"/>
|
||||
<tile id="21" type="WALL"/>
|
||||
<tile id="22" type="WALL"/>
|
||||
<tile id="23" type="WALL"/>
|
||||
<tile id="24" type="WALL"/>
|
||||
<tile id="25" type="WALL"/>
|
||||
<tile id="26" type="WALL"/>
|
||||
<tile id="27" type="WALL"/>
|
||||
<tile id="28" type="WALL"/>
|
||||
<tile id="29" type="WALL"/>
|
||||
<tile id="30" type="WALL"/>
|
||||
<tile id="31" type="WALL"/>
|
||||
<tile id="32" type="WALL"/>
|
||||
<tile id="33" type="WALL"/>
|
||||
<tile id="34" type="WALL"/>
|
||||
<tile id="35" type="WALL"/>
|
||||
<tile id="36" type="WALL"/>
|
||||
<tile id="37" type="WALL"/>
|
||||
<tile id="38" type="FLOOR"/>
|
||||
<tile id="39" type="FLOOR"/>
|
||||
<tile id="40" type="FLOOR"/>
|
||||
<tile id="41" type="FLOOR"/>
|
||||
<tile id="42" type="FLOOR"/>
|
||||
<tile id="43" type="FLOOR"/>
|
||||
<tile id="44" type="FLOOR"/>
|
||||
<tile id="45" type="FLOOR"/>
|
||||
<tile id="46" type="FLOOR"/>
|
||||
<tile id="47" type="FLOOR"/>
|
||||
<tile id="48" type="FLOOR"/>
|
||||
<tile id="49" type="FLOOR"/>
|
||||
<tile id="50" type="FLOOR"/>
|
||||
<tile id="51" type="FLOOR"/>
|
||||
<tile id="52" type="WALL"/>
|
||||
<tile id="53" type="WALL"/>
|
||||
<tile id="54" type="WALL"/>
|
||||
<tile id="55" type="WALL"/>
|
||||
<tile id="56" type="FLOOR"/>
|
||||
<tile id="57" type="FLOOR"/>
|
||||
<tile id="58" type="FLOOR"/>
|
||||
<tile id="59" type="FLOOR"/>
|
||||
<tile id="60" type="FLOOR"/>
|
||||
<tile id="61" type="FLOOR"/>
|
||||
<tile id="62" type="FLOOR"/>
|
||||
<tile id="63" type="FLOOR"/>
|
||||
<tile id="64" type="FLOOR"/>
|
||||
<tile id="65" type="FLOOR"/>
|
||||
<tile id="66" type="FLOOR"/>
|
||||
<tile id="67" type="FLOOR"/>
|
||||
<tile id="68" type="FLOOR"/>
|
||||
<tile id="69" type="FLOOR"/>
|
||||
<tile id="70" type="WALL"/>
|
||||
<tile id="71" type="WALL"/>
|
||||
<tile id="72" type="WALL"/>
|
||||
<tile id="73" type="WALL"/>
|
||||
<tile id="74" type="WALL"/>
|
||||
<tile id="75" type="WALL"/>
|
||||
<tile id="76" type="WALL"/>
|
||||
<tile id="77" type="WALL"/>
|
||||
<tile id="78" type="WALL"/>
|
||||
<tile id="79" type="WALL"/>
|
||||
<tile id="80" type="WALL"/>
|
||||
<tile id="81" type="WALL"/>
|
||||
<tile id="82" type="WALL"/>
|
||||
<tile id="83" type="WALL"/>
|
||||
<tile id="84" type="WALL"/>
|
||||
<tile id="85" type="WALL"/>
|
||||
<tile id="86" type="WALL"/>
|
||||
<tile id="87" type="WALL"/>
|
||||
<tile id="88" type="WALL"/>
|
||||
<tile id="89" type="WALL"/>
|
||||
<tile id="90" type="WALL"/>
|
||||
<tile id="91" type="WALL"/>
|
||||
<tile id="92" type="WALL"/>
|
||||
<tile id="93" type="WALL"/>
|
||||
<tile id="94" type="WALL"/>
|
||||
<tile id="95" type="WALL"/>
|
||||
<tile id="96" type="WALL"/>
|
||||
<tile id="97" type="WALL"/>
|
||||
<tile id="98" type="WALL"/>
|
||||
<tile id="99" type="WALL"/>
|
||||
<tile id="100" type="WALL"/>
|
||||
<tile id="101" type="WALL"/>
|
||||
<tile id="102" type="WALL"/>
|
||||
<tile id="103" type="WALL"/>
|
||||
<tile id="104" type="WALL"/>
|
||||
<tile id="105" type="WALL"/>
|
||||
<tile id="106" type="WALL"/>
|
||||
<tile id="107" type="WALL"/>
|
||||
<tile id="108" type="WALL"/>
|
||||
<tile id="109" type="WALL"/>
|
||||
<tile id="110" type="WALL"/>
|
||||
<tile id="111" type="WALL"/>
|
||||
<tile id="112" type="WALL"/>
|
||||
<tile id="113" type="WALL"/>
|
||||
<tile id="114" type="WALL"/>
|
||||
<tile id="115" type="WALL"/>
|
||||
<tile id="116" type="WALL"/>
|
||||
<tile id="117" type="WALL"/>
|
||||
<tile id="118" type="WALL"/>
|
||||
<tile id="119" type="WALL"/>
|
||||
<tile id="126" type="WALL"/>
|
||||
<tile id="127" type="WALL"/>
|
||||
<tile id="128" type="WALL"/>
|
||||
<tile id="129" type="WALL"/>
|
||||
<tile id="130" type="WALL"/>
|
||||
<tile id="131" type="WALL"/>
|
||||
<tile id="132" type="WALL"/>
|
||||
<tile id="133" type="WALL"/>
|
||||
<tile id="134" type="WALL"/>
|
||||
<tile id="135" type="WALL"/>
|
||||
<tile id="136" type="WALL"/>
|
||||
<tile id="137" type="WALL"/>
|
||||
<tile id="144" type="WALL"/>
|
||||
<tile id="145" type="WALL"/>
|
||||
<tile id="146" type="WALL"/>
|
||||
<tile id="147" type="WALL"/>
|
||||
<tile id="148" type="WALL"/>
|
||||
<tile id="149" type="WALL"/>
|
||||
<tile id="150" type="WALL"/>
|
||||
<tile id="151" type="WALL"/>
|
||||
<tile id="152" type="WALL"/>
|
||||
<tile id="153" type="WALL"/>
|
||||
<tile id="162" type="WALL"/>
|
||||
<tile id="163" type="WALL"/>
|
||||
<tile id="164" type="WALL"/>
|
||||
<tile id="165" type="WALL"/>
|
||||
<tile id="166" type="WALL"/>
|
||||
<tile id="167" type="WALL"/>
|
||||
<tile id="168" type="WALL"/>
|
||||
<tile id="169" type="WALL"/>
|
||||
<tile id="170" type="WALL"/>
|
||||
<tile id="171" type="WALL"/>
|
||||
<tile id="180" type="WALL"/>
|
||||
<tile id="181" type="WALL"/>
|
||||
<tile id="182" type="WALL"/>
|
||||
<tile id="183" type="WALL"/>
|
||||
<tile id="184" type="WALL"/>
|
||||
<tile id="185" type="WALL"/>
|
||||
<tile id="186" type="WALL"/>
|
||||
<tile id="187" type="WALL"/>
|
||||
<tile id="188" type="WALL"/>
|
||||
<tile id="189" type="WALL"/>
|
||||
<tile id="198" type="WALL"/>
|
||||
<tile id="199" type="WALL"/>
|
||||
<tile id="200" type="WALL"/>
|
||||
<tile id="201" type="WALL"/>
|
||||
<tile id="202" type="WALL"/>
|
||||
<tile id="203" type="WALL"/>
|
||||
<tile id="204" type="WALL"/>
|
||||
<tile id="205" type="WALL"/>
|
||||
<tile id="206" type="WALL"/>
|
||||
<tile id="207" type="WALL"/>
|
||||
</tileset>
|
44
examples/the-dungeon-keepers-lament/maps/levels/level1.tmx
Normal file
44
examples/the-dungeon-keepers-lament/maps/levels/level1.tmx
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="5">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RRRRRR"/>
|
||||
<property name="ITEMS" value="KEY"/>
|
||||
<property name="NAME" value="Keys open doors"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Background" width="22" height="20" offsetx="0" offsety="0.181818">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,0,0,
|
||||
0,0,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,0,0,
|
||||
0,0,37,38,39,40,41,42,43,44,45,52,47,48,49,50,51,52,53,54,0,0,
|
||||
0,0,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,0,0,
|
||||
0,0,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,
|
||||
0,0,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="1" name="STAIRS" x="135.932" y="73.1136">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="HERO" x="57.7273" y="72.1818">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="DOOR" x="104.75" y="72.25">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
41
examples/the-dungeon-keepers-lament/maps/levels/level2.tmx
Normal file
41
examples/the-dungeon-keepers-lament/maps/levels/level2.tmx
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="3">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="DDDL"/>
|
||||
<property name="ITEMS" value="DOOR"/>
|
||||
<property name="NAME" value="You can't go through locked doors"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Background" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,2,3,16,17,18,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,19,20,21,34,35,36,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,37,38,39,52,53,54,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,55,56,57,70,71,72,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,1,2,6,7,1073741951,1073741952,43,44,147,148,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,19,20,24,25,1073741933,1073741934,61,62,165,166,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,37,38,2147483694,2147483693,41,42,47,48,183,184,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,55,56,2147483712,2147483711,59,60,65,66,201,202,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,73,74,75,76,109,110,41,42,165,166,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,91,92,93,94,127,128,59,60,183,184,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,37,38,45,46,147,148,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,55,56,63,64,165,166,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,73,74,75,76,89,90,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,91,92,93,94,107,108,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="1" name="HERO" x="104.789" y="38.731">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="STAIRS" x="87.575" y="71.4371">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
47
examples/the-dungeon-keepers-lament/maps/levels/level3.tmx
Normal file
47
examples/the-dungeon-keepers-lament/maps/levels/level3.tmx
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="5">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RRDURRRRR"/>
|
||||
<property name="ITEMS" value="DOOR"/>
|
||||
<property name="NAME" value="Keys open more than one door"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,1,2,3,4,5,6,7,8,9,10,15,16,17,18,0,0,0,0,
|
||||
0,0,0,0,19,20,21,22,23,24,25,26,27,28,33,34,35,36,0,0,0,0,
|
||||
0,0,0,0,37,38,39,40,41,42,43,44,45,46,51,52,53,54,0,0,0,0,
|
||||
0,0,0,0,55,56,57,58,59,60,61,62,63,64,69,70,71,72,0,0,0,0,
|
||||
0,0,0,0,73,74,109,110,1073741885,1073741886,2147483758,2147483757,81,82,87,88,89,90,0,0,0,0,
|
||||
0,0,0,0,91,92,127,128,1073741867,1073741868,2147483776,2147483775,99,100,105,106,107,108,0,0,0,0,
|
||||
0,0,0,0,0,0,73,74,75,76,2147483722,2147483721,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,91,92,93,94,2147483740,2147483739,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="1" name="HERO" x="56" y="72.375">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="KEY" x="72" y="87.375">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="DOOR" x="101.625" y="72.875">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="STAIRS" x="118.875" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
44
examples/the-dungeon-keepers-lament/maps/levels/level4.tmx
Normal file
44
examples/the-dungeon-keepers-lament/maps/levels/level4.tmx
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="4" nextobjectid="4">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="LLLLLLL"/>
|
||||
<property name="ITEMS" value="SWORD"/>
|
||||
<property name="NAME" value="You need a sword to kill slimes"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,0,0,
|
||||
0,0,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,0,0,
|
||||
0,0,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,0,0,
|
||||
0,0,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,0,0,
|
||||
0,0,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,
|
||||
0,0,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="3" name="Object Layer 1">
|
||||
<object id="1" name="HERO" x="136" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="SLIME" x="72" y="73.3333">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="STAIRS" x="41.6667" y="73.3333">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
41
examples/the-dungeon-keepers-lament/maps/levels/level5.tmx
Normal file
41
examples/the-dungeon-keepers-lament/maps/levels/level5.tmx
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="4">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="LLRRRRR"/>
|
||||
<property name="ITEMS" value="SLIME,SWORD"/>
|
||||
<property name="NAME" value="It takes time to kill slimes"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Background" width="22" height="20" offsetx="0" offsety="0.181818">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,0,0,
|
||||
0,0,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,0,0,
|
||||
0,0,37,38,39,40,41,42,43,44,45,52,47,48,49,50,51,52,53,54,0,0,
|
||||
0,0,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,0,0,
|
||||
0,0,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,
|
||||
0,0,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="1" name="STAIRS" x="136.182" y="72.3636">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="HERO" x="72.7273" y="72.1818">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
50
examples/the-dungeon-keepers-lament/maps/levels/level6.tmx
Normal file
50
examples/the-dungeon-keepers-lament/maps/levels/level6.tmx
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="6">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="URULUUUUL"/>
|
||||
<property name="ITEMS" value="DOOR"/>
|
||||
<property name="NAME" value="You can only hold one item"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Backgrounds" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,1,2,3,4,5,5,6,12,13,14,15,16,17,18,0,0,0,0,
|
||||
0,0,0,0,19,20,21,22,23,23,24,30,31,32,33,34,35,36,0,0,0,0,
|
||||
0,0,0,0,37,38,39,40,41,42,43,44,39,40,43,44,1073741989,1073741990,0,0,0,0,
|
||||
0,0,0,0,55,56,57,58,59,60,61,62,57,58,61,62,1073741971,1073741972,0,0,0,0,
|
||||
0,0,0,0,73,74,75,76,77,78,109,110,43,44,111,112,113,114,0,0,0,0,
|
||||
0,0,0,0,91,92,93,94,95,96,127,128,61,62,129,130,131,132,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,145,146,45,46,47,48,147,148,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,163,164,63,64,65,66,165,166,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,181,182,47,48,43,44,183,184,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,199,200,65,66,61,62,201,202,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1073741987,1073741988,49,50,51,52,1073741989,1073741990,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1073741969,1073741970,67,68,69,70,1073741971,1073741972,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,73,74,85,86,87,88,89,90,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,91,92,103,104,105,106,107,108,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="1" name="HERO" x="103.918" y="105.197">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="STAIRS" x="88" y="40.6774">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="SLIME" x="103.749" y="40">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="SWORD" x="103.749" y="89.11">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="5" name="KEY" x="121.191" y="75.7318">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="8">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RULDRULDRULD"/>
|
||||
<property name="ITEMS" value="DOOR,SWORD,SLIME,SQUID_UP"/>
|
||||
<property name="NAME" value="Now they're just going in circles"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Backgrounds" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,1,2,7,8,3,4,13,7,8,9,10,11,12,13,14,15,3221225564,3221225563,
|
||||
0,0,0,0,19,20,25,26,21,22,31,25,26,27,28,29,30,31,32,33,3221225546,3221225545,
|
||||
0,0,0,0,37,38,41,42,45,46,47,48,49,50,51,52,41,42,41,42,147,148,
|
||||
0,0,0,0,55,56,59,60,63,64,65,66,67,68,69,70,59,60,59,60,165,166,
|
||||
1,2,1073741917,1073741918,1073741951,1073741952,41,42,41,42,43,44,45,46,47,48,49,50,51,52,183,184,
|
||||
19,20,1073741899,1073741900,1073741933,1073741934,59,60,59,60,61,62,63,64,65,66,67,68,69,70,201,202,
|
||||
145,146,41,42,41,42,45,46,41,42,41,42,41,42,45,46,41,42,49,50,147,148,
|
||||
163,164,59,60,59,60,63,64,59,60,59,60,59,60,63,64,57,58,59,60,165,166,
|
||||
181,182,39,40,41,42,43,44,45,46,47,48,49,50,45,46,2147483758,2147483757,77,78,2147483722,2147483721,
|
||||
199,200,57,58,59,60,61,62,63,64,65,66,67,68,63,64,2147483776,2147483775,95,96,2147483740,2147483739,
|
||||
73,74,109,110,49,50,39,40,41,42,43,44,45,46,47,48,147,148,0,0,0,0,
|
||||
91,92,127,128,67,68,57,58,59,60,61,62,63,64,65,66,165,166,0,0,0,0,
|
||||
0,0,37,38,41,42,39,40,41,42,43,44,45,46,47,48,183,184,0,0,0,0,
|
||||
0,0,55,56,59,60,57,58,59,60,61,62,63,64,65,66,201,202,0,0,0,0,
|
||||
0,0,73,74,109,110,43,44,45,46,47,48,49,50,51,52,147,148,0,0,0,0,
|
||||
0,0,91,92,127,128,61,62,63,64,65,66,67,68,69,70,165,166,0,0,0,0,
|
||||
0,0,0,0,181,182,41,42,43,44,45,46,47,48,2147483758,2147483757,2147483722,2147483721,0,0,0,0,
|
||||
0,0,0,0,199,200,59,60,61,62,63,64,65,66,2147483776,2147483775,2147483740,2147483739,0,0,0,0,
|
||||
0,0,0,0,73,74,83,84,77,78,79,80,81,82,2147483722,2147483721,0,0,0,0,0,0,
|
||||
0,0,0,0,91,92,101,102,95,96,97,98,99,100,2147483740,2147483739,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="6" name="HERO" x="72" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="7" name="STAIRS" x="120" y="40">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="7">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RRRRRRDDRR"/>
|
||||
<property name="ITEMS" value="DOOR_SWITCHED_OPEN,SWITCH"/>
|
||||
<property name="NAME" value="Be careful of the spikes"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,0,0,
|
||||
0,0,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,0,0,
|
||||
0,0,37,38,39,40,47,48,39,48,43,44,47,48,51,52,51,52,1073741895,1073741896,0,0,
|
||||
0,0,55,56,57,58,65,66,69,70,61,62,65,66,61,70,69,70,1073741877,1073741878,0,0,
|
||||
0,0,145,146,51,52,47,48,1073741881,1073741882,51,48,47,48,47,48,43,44,147,148,0,0,
|
||||
0,0,163,164,69,70,65,66,1073741863,1073741864,61,70,65,66,65,66,61,62,165,166,0,0,
|
||||
0,0,181,182,39,52,47,48,43,44,51,52,39,50,51,52,51,50,183,184,0,0,
|
||||
0,0,199,200,69,70,65,66,61,62,69,70,61,62,69,70,69,70,201,202,0,0,
|
||||
0,0,1073741987,1073741988,51,52,43,48,51,52,39,50,51,52,51,52,39,50,53,54,0,0,
|
||||
0,0,1073741969,1073741970,69,70,61,62,69,70,69,70,69,70,69,70,69,70,71,72,0,0,
|
||||
0,0,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,
|
||||
0,0,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="1" name="HERO" x="38.0855" y="71.8675">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="SPIKES_DOWN" x="120.066" y="90.8026">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="SWITCH" x="86.284" y="89.7268">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="STAIRS" x="120.496" y="108.447">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="6" name="SPIKES" x="103.283" y="106.51">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="18">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="ULULULULULULULUL"/>
|
||||
<property name="ITEMS" value="DOOR_SWITCHED_OPEN,SWITCH,SWITCH,DOOR_SWITCHED"/>
|
||||
<property name="NAME" value="Why do people leave things in awkward places?"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,1,2,3,4,5,6,9,10,11,12,13,14,15,16,17,18,0,0,
|
||||
0,0,0,0,19,20,21,22,23,24,27,28,29,30,31,32,33,34,35,36,0,0,
|
||||
0,0,0,0,37,38,39,40,51,52,51,52,41,42,45,46,39,40,53,54,0,0,
|
||||
0,0,0,0,55,56,57,58,69,70,69,70,59,60,63,64,57,58,71,72,0,0,
|
||||
0,0,0,0,2147483762,2147483761,2147483760,2147483759,51,52,39,40,39,40,51,52,45,46,147,148,0,0,
|
||||
0,0,0,0,2147483780,2147483779,2147483778,2147483777,69,70,57,58,57,58,69,70,63,64,165,166,0,0,
|
||||
0,0,0,0,145,146,39,40,39,40,45,46,51,52,45,46,45,46,183,184,0,0,
|
||||
0,0,0,0,163,164,57,58,57,58,63,64,69,70,63,64,63,64,201,202,0,0,
|
||||
0,0,0,0,181,182,45,46,41,42,51,52,45,46,51,52,39,40,53,54,0,0,
|
||||
0,0,0,0,199,200,63,64,59,60,69,70,63,64,69,70,57,58,71,72,0,0,
|
||||
0,0,0,0,73,74,75,76,77,78,79,80,81,82,83,86,87,88,89,90,0,0,
|
||||
0,0,0,0,91,92,93,94,95,96,97,98,99,100,101,104,105,106,107,108,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="7" name="HERO" x="134.753" y="104.844">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="8" name="STAIRS" x="56" y="57.7214">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="10" name="SPIKES_DOWN" x="73.2137" y="71.2773">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="12" name="SLIME" x="71.4924" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="15" name="SPIKES" x="88.9213" y="56.8607">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="17" name="SWORD" x="89.3516" y="89.9972">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="15">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RRRRRRRRRRRRRR"/>
|
||||
<property name="ITEMS" value="DOOR,SQUID_DOWN,DOOR_SWITCHED,DOOR_SWITCHED_OPEN"/>
|
||||
<property name="NAME" value="Why are they running right at it?"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,14,3221225564,3221225563,0,0,0,0,
|
||||
0,0,0,0,19,20,21,22,23,24,25,26,27,28,29,32,3221225546,3221225545,0,0,0,0,
|
||||
0,0,1,2,1073741951,1073741952,43,44,39,40,49,50,41,42,39,40,3221225600,3221225599,6,7,17,18,
|
||||
0,0,19,20,1073741933,1073741934,61,62,57,58,67,68,59,60,57,58,3221225582,3221225581,24,25,35,36,
|
||||
0,0,145,146,43,44,49,50,39,40,41,42,39,40,41,42,43,44,39,40,53,54,
|
||||
0,0,163,164,61,62,67,68,57,58,59,60,57,58,59,60,61,62,57,58,71,72,
|
||||
0,0,181,182,39,40,43,44,39,40,43,44,41,42,39,40,41,42,39,40,147,148,
|
||||
0,0,199,200,57,58,61,62,57,58,61,62,59,60,57,58,59,60,57,58,165,166,
|
||||
0,0,37,38,43,44,41,42,41,42,49,50,39,40,49,50,39,40,39,40,183,184,
|
||||
0,0,55,56,61,62,59,60,59,60,67,68,57,58,67,68,57,58,57,58,201,202,
|
||||
0,0,1073741987,1073741988,43,44,39,40,41,42,41,42,39,40,41,42,41,42,49,50,147,148,
|
||||
0,0,1073741969,1073741970,61,62,57,58,59,60,59,60,57,58,59,60,59,60,67,68,165,166,
|
||||
0,0,145,146,39,40,39,40,39,40,39,40,39,40,39,40,41,42,39,40,183,184,
|
||||
0,0,163,164,57,58,57,58,57,58,57,58,57,58,57,58,59,60,57,58,201,202,
|
||||
0,0,37,38,43,44,41,42,39,40,41,42,41,42,43,44,39,40,39,40,147,148,
|
||||
0,0,55,56,61,62,59,60,57,58,59,60,59,60,61,62,57,58,57,58,165,166,
|
||||
0,0,3221225508,3221225507,75,76,77,78,79,80,109,110,39,40,39,40,39,40,2147483758,2147483757,89,90,
|
||||
0,0,3221225490,3221225489,93,94,95,96,97,98,127,128,57,58,57,58,57,58,2147483776,2147483775,107,108,
|
||||
0,0,0,0,0,0,0,0,0,0,73,74,83,84,85,86,87,88,3221225492,3221225491,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,91,92,101,102,103,104,105,106,3221225474,3221225473,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="7" name="HERO" x="39.3138" y="75.0303">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="9" name="SPIKES_DOWN" x="103.552" y="74.7733">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="10" name="SQUID_UP" x="103.295" y="141.324">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="11" name="SWORD" x="103.552" y="122.31">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="12" name="SWITCH" x="135.414" y="75.5442">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="13" name="STAIRS" x="153.144" y="72.9747">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="14" name="SLIME" x="121.282" y="72.9747">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="7">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RRRRRRRRR"/>
|
||||
<property name="ITEMS" value="SWORD,SQUID_DOWN,HERO"/>
|
||||
<property name="NAME" value="Squids keep stealing the treasure. Why did I put them here again?"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,17,18,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,19,20,21,22,23,24,25,26,35,36,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,145,146,45,46,47,48,49,50,147,148,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,163,164,63,64,65,66,67,68,165,166,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,181,182,45,46,47,48,45,46,53,54,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,199,200,63,64,65,66,63,64,71,72,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,73,74,109,110,43,44,2147483758,2147483757,89,90,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,91,92,127,128,61,62,2147483776,2147483775,107,108,0,0,0,0,
|
||||
0,0,1,2,3,4,5,6,7,8,1073741951,1073741952,45,46,3221225600,3221225599,14,15,17,18,0,0,
|
||||
0,0,19,20,21,22,23,24,25,26,1073741933,1073741934,63,64,3221225582,3221225581,32,33,35,36,0,0,
|
||||
0,0,37,38,39,40,39,40,41,42,43,44,45,46,47,48,49,50,53,54,0,0,
|
||||
0,0,55,56,57,58,57,58,59,60,61,62,63,64,65,66,67,68,71,72,0,0,
|
||||
0,0,73,74,2147483729,75,76,77,78,79,109,110,47,48,2147483758,2147483757,86,87,89,90,0,0,
|
||||
0,0,91,92,2147483747,93,94,95,96,97,127,128,65,66,2147483776,2147483775,104,105,107,108,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,145,146,43,44,147,148,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,163,164,61,62,165,166,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,181,182,45,46,183,184,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,199,200,63,64,201,202,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,73,74,75,76,3221225492,3221225491,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,91,92,93,94,3221225474,3221225473,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="2" name="DOOR" x="120.114" y="92.7461">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="SLIME" x="104.552" y="92.7253">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="STAIRS" x="136.268" y="93.2461">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="6" name="KEY" x="104" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="6">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="DDDRRRR"/>
|
||||
<property name="ITEMS" value="SQUID_DOWN,DOOR_SWITCHED_OPEN,DOOR_SWITCHED,KEY"/>
|
||||
<property name="NAME" value="I'm sorry squid"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,1,2,6,7,17,18,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,19,20,24,25,35,36,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,37,38,39,40,147,148,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,55,56,57,58,165,166,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,145,146,41,42,183,184,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,163,164,59,60,201,202,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,181,182,43,44,3221225600,3221225599,13,14,15,16,17,18,0,0,0,0,
|
||||
0,0,0,0,0,0,199,200,61,62,3221225582,3221225581,31,32,33,34,35,36,0,0,0,0,
|
||||
0,0,0,0,0,0,1073742023,1073742024,39,40,41,42,43,44,43,44,53,54,0,0,0,0,
|
||||
0,0,0,0,0,0,1073742005,1073742006,57,58,59,60,61,62,61,62,71,72,0,0,0,0,
|
||||
0,0,0,0,0,0,1073741987,1073741988,47,48,2147483758,2147483757,75,76,80,81,89,90,0,0,0,0,
|
||||
0,0,0,0,0,0,1073741969,1073741970,65,66,2147483776,2147483775,93,94,98,99,107,108,0,0,0,0,
|
||||
0,0,0,0,0,0,37,38,49,50,147,148,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,55,56,67,68,165,166,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,73,74,75,76,89,90,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,91,92,93,94,107,108,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="1" name="HERO" x="73.4886" y="42.9112">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="SWITCH" x="71.433" y="125.393">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="SPIKES" x="105.351" y="91.2183">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="STAIRS" x="120.511" y="89.6766">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="5" name="DOOR" x="88.3919" y="87.8779">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="8">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RDRDRDRRRDDDRR"/>
|
||||
<property name="ITEMS" value="SWITCH,SWORD,DOOR,SLIME,SLIME"/>
|
||||
<property name="NAME" value="The key is right there!"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,2,5,6,1073741931,1073741932,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,19,20,23,24,1073741913,1073741914,0,0,0,0,0,0,
|
||||
0,0,3221225580,3221225579,5,6,7,8,9,5,1073741951,1073741952,43,44,3221225600,3221225599,5,6,2147483650,2147483649,0,0,
|
||||
0,0,3221225562,3221225561,23,24,25,26,27,23,1073741933,1073741934,61,62,3221225582,3221225581,23,24,2147483668,2147483667,0,0,
|
||||
0,0,37,38,47,48,39,40,41,42,47,48,39,40,45,46,41,42,53,54,0,0,
|
||||
0,0,55,56,65,66,57,58,59,60,65,66,57,58,63,64,59,60,71,72,0,0,
|
||||
0,0,1073741987,1073741988,39,40,47,48,47,48,41,42,39,40,47,48,45,46,147,148,0,0,
|
||||
0,0,1073741969,1073741970,57,58,65,66,65,66,59,60,57,58,65,66,63,64,165,166,0,0,
|
||||
0,0,37,38,39,40,39,40,41,42,39,40,39,40,47,48,41,42,183,184,0,0,
|
||||
0,0,55,56,57,58,57,58,59,60,57,58,57,58,65,66,59,60,201,202,0,0,
|
||||
0,0,145,146,47,48,47,48,47,48,47,48,41,42,45,46,111,112,113,114,0,0,
|
||||
0,0,163,164,65,66,65,66,65,66,65,66,59,60,63,64,129,130,131,132,0,0,
|
||||
0,0,37,38,47,48,43,44,47,48,41,42,149,150,39,40,39,40,53,54,0,0,
|
||||
0,0,55,56,65,66,61,62,65,66,59,60,167,168,57,58,57,58,71,72,0,0,
|
||||
0,0,73,74,75,76,77,78,79,80,81,82,185,186,85,86,87,88,89,90,0,0,
|
||||
0,0,91,92,93,94,95,96,97,98,99,100,203,204,103,104,105,106,107,108,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="1" name="HERO" x="40" y="88">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="STAIRS" x="136" y="120">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="DOOR" x="120" y="120">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="KEY" x="104" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="5" name="SQUID_DOWN" x="104" y="40">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="6" name="DOOR_SWITCHED" x="104" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="22">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="DDDRRRRRRRRRRRRU"/>
|
||||
<property name="ITEMS" value="SQUID_UP,SQUID_DOWN,SWITCH,SPIKES,DOOR,KEY"/>
|
||||
<property name="NAME" value="We used to have treasure in there"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Backgrounds" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,2147483650,2147483649,0,0,
|
||||
0,0,0,0,0,0,19,20,21,22,23,24,25,26,27,28,29,30,2147483668,2147483667,0,0,
|
||||
0,0,0,0,0,0,2147483814,2147483813,45,46,49,50,45,46,51,52,45,46,2147483794,2147483793,0,0,
|
||||
0,0,0,0,0,0,2147483832,2147483831,63,64,67,68,63,64,69,70,63,64,2147483812,2147483811,0,0,
|
||||
0,0,0,0,0,0,37,38,51,52,45,46,49,50,43,44,47,48,3221225600,3221225599,3221225564,3221225563,
|
||||
0,0,0,0,0,0,55,56,69,70,63,64,67,68,61,62,65,66,3221225582,3221225581,3221225546,3221225545,
|
||||
1073741915,1073741916,5,6,1073742029,1073742030,153,154,45,46,45,46,43,44,47,48,51,52,39,40,147,148,
|
||||
1073741897,1073741898,23,24,1073742011,1073742012,171,172,63,64,63,64,61,62,65,66,69,70,57,58,165,166,
|
||||
3221225638,3221225637,39,40,1073741993,1073741994,153,154,43,44,43,44,43,44,51,52,47,48,47,48,183,184,
|
||||
3221225620,3221225619,57,58,1073741975,1073741976,171,172,61,62,61,62,61,62,69,70,65,66,65,66,201,202,
|
||||
3221225638,3221225637,39,40,39,40,1073741991,1073741992,45,46,51,52,41,42,47,48,47,48,51,52,147,148,
|
||||
3221225620,3221225619,57,58,57,58,1073741973,1073741974,63,64,69,70,59,60,65,66,65,66,69,70,165,166,
|
||||
145,146,45,46,39,40,39,40,39,40,45,46,51,52,41,42,51,52,49,50,147,148,
|
||||
163,164,63,64,57,58,57,58,57,58,63,64,69,70,59,60,69,70,67,68,165,166,
|
||||
145,146,47,48,2147483758,2147483757,79,80,81,82,109,110,45,46,47,48,49,50,47,48,183,184,
|
||||
163,164,65,66,2147483776,2147483775,97,98,99,100,127,128,63,64,65,66,67,68,65,66,201,202,
|
||||
1073741843,1073741844,79,80,2147483722,2147483721,0,0,0,0,73,74,1073741847,1073741848,1073741849,1073741850,1073741851,1073741852,1073741853,1073741854,2147483722,2147483721,
|
||||
1073741825,1073741826,97,98,2147483740,2147483739,0,0,0,0,91,92,1073741829,1073741830,1073741831,1073741832,1073741833,1073741834,1073741835,1073741836,2147483740,2147483739,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="12" name="HERO" x="24" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="18" name="DOOR" x="24" y="104">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="20" name="SWORD" x="88" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="21" name="STAIRS" x="120" y="88">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="12">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="DDDRRRDDDLLL"/>
|
||||
<property name="ITEMS" value="SWITCH,DOOR"/>
|
||||
<property name="NAME" value="Why did I put that door there?"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Backgrounds" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,1,2,15,16,17,18,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,19,20,33,34,35,36,0,0,0,0,0,0,0,0,0,0,
|
||||
1,2,6,7,8,9,117,118,43,44,3221225600,3221225599,17,18,0,0,0,0,0,0,0,0,
|
||||
19,20,24,25,26,27,135,136,61,62,3221225582,3221225581,35,36,0,0,0,0,0,0,0,0,
|
||||
145,146,39,40,45,46,1073741991,1073741992,45,46,51,52,53,54,0,0,0,0,0,0,0,0,
|
||||
163,164,57,58,63,64,1073741973,1073741974,63,64,69,70,71,72,0,0,0,0,0,0,0,0,
|
||||
181,182,45,46,45,46,47,48,49,50,39,40,3221225600,3221225599,11,12,13,14,15,16,17,18,
|
||||
199,200,63,64,63,64,65,66,67,68,57,58,3221225582,3221225581,29,30,31,32,33,34,35,36,
|
||||
145,146,45,46,47,48,45,46,45,46,39,40,43,44,47,48,39,40,45,46,147,148,
|
||||
163,164,63,64,65,66,63,64,63,64,57,58,61,62,65,66,57,58,63,64,165,166,
|
||||
181,182,47,48,39,40,149,150,47,48,47,48,149,150,39,40,45,46,47,48,183,184,
|
||||
199,200,65,66,57,58,167,168,65,66,65,66,167,168,57,58,63,64,65,66,201,202,
|
||||
37,38,45,46,151,152,153,154,39,40,111,112,119,120,47,48,51,52,47,48,165,166,
|
||||
55,56,63,64,169,170,171,172,57,58,129,130,137,138,65,66,69,70,65,66,183,184,
|
||||
73,74,75,76,187,188,189,190,47,48,39,40,47,48,51,52,51,52,39,40,147,148,
|
||||
91,92,93,94,205,206,207,208,65,66,57,58,65,66,69,70,69,70,57,58,165,166,
|
||||
0,0,0,0,0,0,145,146,47,48,39,40,149,150,51,52,2147483758,2147483757,77,78,2147483722,2147483721,
|
||||
0,0,0,0,0,0,163,164,65,66,57,58,167,168,69,70,2147483776,2147483775,95,96,2147483740,2147483739,
|
||||
0,0,0,0,0,0,73,74,75,76,77,78,185,186,79,80,2147483722,2147483721,0,0,0,0,
|
||||
0,0,0,0,0,0,91,92,93,94,95,96,203,204,97,98,2147483740,2147483739,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="6" name="DOOR_SWITCHED" x="72" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="7" name="DOOR_SWITCHED_OPEN" x="104" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="8" name="HERO" x="72" y="24">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="9" name="SQUID_DOWN" x="24" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="10" name="SPIKES_DOWN" x="104" y="120">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="11" name="STAIRS" x="88" y="120">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="18">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RRDDRRRRRR"/>
|
||||
<property name="ITEMS" value="KEY,SQUID_DOWN,SQUID_DOWN"/>
|
||||
<property name="NAME" value="Why does no one look where they're going?"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Backgrounds" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,2147483650,2147483649,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,19,20,21,22,23,24,25,26,2147483668,2147483667,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,145,146,43,44,47,48,49,50,3221225600,3221225599,17,18,0,0,
|
||||
0,0,0,0,0,0,0,0,163,164,61,62,65,66,67,68,3221225582,3221225581,35,36,0,0,
|
||||
0,0,0,0,0,0,0,0,37,38,51,52,39,40,49,50,45,46,53,54,0,0,
|
||||
0,0,0,0,0,0,0,0,55,56,69,70,57,58,67,68,63,64,71,72,0,0,
|
||||
0,0,1,2,8,9,10,11,1073741951,1073741952,51,52,43,44,45,46,49,50,147,148,0,0,
|
||||
0,0,19,20,26,27,28,29,1073741933,1073741934,69,70,61,62,63,64,67,68,165,166,0,0,
|
||||
0,0,37,38,43,44,39,40,45,46,47,48,47,48,47,48,43,44,183,184,0,0,
|
||||
0,0,55,56,61,62,57,58,63,64,65,66,65,66,65,66,61,62,201,202,0,0,
|
||||
0,0,73,74,109,110,49,50,47,48,149,150,43,44,47,48,2147483758,2147483757,89,90,0,0,
|
||||
0,0,91,92,127,128,67,68,65,66,167,168,61,62,65,66,2147483776,2147483775,107,108,0,0,
|
||||
0,0,0,0,73,74,84,85,86,87,185,186,83,79,79,80,2147483722,2147483721,0,0,0,0,
|
||||
0,0,0,0,91,92,102,103,104,105,203,204,101,97,97,98,2147483740,2147483739,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="12" name="HERO" x="40" y="88">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="13" name="DOOR" x="72" y="104">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="14" name="DOOR" x="88" y="88">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="15" name="SPIKES" x="88" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="16" name="SWITCH" x="120" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="17" name="STAIRS" x="120" y="88">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="10">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RRRRRRRRRRRRRRR"/>
|
||||
<property name="ITEMS" value="SWITCH,SWITCH,SWITCH,DOOR_SWITCHED,DOOR_SWITCHED_OPEN,SQUID_UP,SQUID_UP,SQUID_DOWN,SQUID_DOWN"/>
|
||||
<property name="NAME" value="DO I HAVE TO DO EVERYTHING?"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,0,0,
|
||||
0,0,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,0,0,
|
||||
0,0,37,38,41,42,43,44,45,46,47,48,49,50,51,52,49,50,53,54,0,0,
|
||||
0,0,55,56,59,60,61,62,63,64,65,66,67,68,69,70,67,68,71,72,0,0,
|
||||
0,0,37,38,49,50,39,40,41,42,43,44,45,46,47,48,49,50,53,54,0,0,
|
||||
0,0,55,56,67,68,57,58,59,60,61,62,63,64,65,66,67,68,71,72,0,0,
|
||||
0,0,145,146,41,42,43,44,45,46,47,48,49,50,51,52,49,50,147,148,0,0,
|
||||
0,0,163,164,59,60,61,62,63,64,65,66,67,68,69,70,67,68,165,166,0,0,
|
||||
0,0,37,38,49,50,39,40,41,42,43,44,45,46,47,48,49,50,183,184,0,0,
|
||||
0,0,55,56,67,68,57,58,59,60,61,62,63,64,65,66,67,68,201,202,0,0,
|
||||
0,0,37,38,41,42,43,44,45,46,47,48,49,50,51,52,49,50,53,54,0,0,
|
||||
0,0,55,56,59,60,61,62,63,64,65,66,67,68,69,70,67,68,71,72,0,0,
|
||||
0,0,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,
|
||||
0,0,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,0,0,
|
||||
1,2,3,4,3,4,5,6,7,8,9,10,11,12,13,14,15,16,15,16,17,18,
|
||||
19,20,21,22,21,22,23,24,25,26,27,28,29,30,31,32,33,34,33,34,35,36,
|
||||
37,38,39,40,39,40,41,42,43,44,45,46,47,48,49,50,51,52,51,52,53,54,
|
||||
55,56,57,58,57,58,59,60,61,62,63,64,65,66,67,68,69,70,69,70,71,72,
|
||||
73,74,75,76,75,76,77,78,79,80,81,82,83,84,85,86,87,88,87,88,89,90,
|
||||
91,92,93,94,93,94,95,96,97,98,99,100,101,102,103,104,105,106,105,106,107,108
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Object Layer 1">
|
||||
<object id="1" name="STAIRS" x="151.349" y="138.188">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="2" name="HERO" x="21.7659" y="137.682">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="3" name="SPIKES" x="118.447" y="140.213">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="4" name="SPIKES" x="102.755" y="142.744">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="5" name="DOOR_SWITCHED_OPEN" x="55.6802" y="139.2">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="6" name="SPIKES" x="39.7354" y="137.429">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="7" name="SPIKES_DOWN" x="71.3719" y="141.984">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="8" name="DOOR_SWITCHED" x="88.5821" y="134.645">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="9" name="SPIKES_DOWN" x="135.151" y="141.984">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="14">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RLRRRD"/>
|
||||
<property name="ITEMS" value="DOOR_SWITCHED"/>
|
||||
<property name="NAME" value="Switches toggle things"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Backgrounds" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,1,2,3,4,5,5,6,12,13,14,15,16,17,18,0,0,0,0,
|
||||
0,0,0,0,19,20,21,22,23,23,24,30,31,32,33,34,35,36,0,0,0,0,
|
||||
0,0,0,0,37,38,39,40,41,42,43,44,39,40,43,44,1073741989,1073741990,0,0,0,0,
|
||||
0,0,0,0,55,56,57,58,59,60,61,62,57,58,61,62,1073741971,1073741972,0,0,0,0,
|
||||
0,0,0,0,73,74,75,76,77,78,109,110,43,44,111,112,113,114,0,0,0,0,
|
||||
0,0,0,0,91,92,93,94,95,96,127,128,61,62,129,130,131,132,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,37,38,49,50,51,52,183,184,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,55,56,67,68,69,70,201,202,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,73,74,75,76,81,82,89,90,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,91,92,93,94,99,100,107,108,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="1" name="HERO" x="72" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="9" name="STAIRS" x="104" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="11" name="SWITCH" x="56" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="13" name="SPIKES" x="120" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="22" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="15">
|
||||
<properties>
|
||||
<property name="DIRECTIONS" value="RDDL"/>
|
||||
<property name="ITEMS" value="DOOR_SWITCHED,DOOR_SWITCHED_OPEN"/>
|
||||
<property name="NAME" value="Squids, they have a mind of their own"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="../level.tsx"/>
|
||||
<layer id="1" name="Backgrounds" width="22" height="20">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,1,2,3,4,2147483650,2147483649,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,19,20,21,22,2147483668,2147483667,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,145,146,51,52,147,148,0,0,0,0,1,2,7,8,9,10,2147483650,2147483649,0,0,
|
||||
0,0,163,164,69,70,165,166,0,0,0,0,19,20,25,26,27,28,2147483668,2147483667,0,0,
|
||||
0,0,181,182,49,50,183,184,0,0,1,2,1073741951,1073741952,39,40,41,42,147,148,0,0,
|
||||
0,0,199,200,67,68,201,202,0,0,19,20,1073741933,1073741934,57,58,59,60,165,166,0,0,
|
||||
0,0,37,38,49,50,2147483794,2147483793,0,0,145,146,39,40,41,42,41,42,183,184,0,0,
|
||||
0,0,55,56,67,68,2147483812,2147483811,0,0,163,164,57,58,59,60,59,60,201,202,0,0,
|
||||
0,0,145,146,49,50,2147483830,2147483829,0,0,181,182,49,50,47,48,49,50,183,184,0,0,
|
||||
0,0,163,164,67,68,2147483848,2147483847,0,0,199,200,67,68,65,66,67,68,201,202,0,0,
|
||||
0,0,181,182,43,44,147,148,0,0,1073741843,1073741844,109,110,39,40,2147483758,2147483757,2147483722,2147483721,0,0,
|
||||
0,0,199,200,61,62,165,166,0,0,1073741825,1073741826,127,128,57,58,2147483776,2147483775,2147483740,2147483739,0,0,
|
||||
0,0,37,38,45,46,183,184,0,0,0,0,1073741843,1073741844,1073741847,1073741848,2147483722,2147483721,0,0,0,0,
|
||||
0,0,55,56,63,64,201,202,0,0,0,0,1073741825,1073741826,1073741829,1073741830,2147483740,2147483739,0,0,0,0,
|
||||
0,0,73,74,77,78,3221225492,3221225491,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,91,92,95,96,3221225474,3221225473,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="2" name="Objects">
|
||||
<object id="8" name="SQUID_DOWN" x="40" y="40">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="9" name="SWITCH" x="40" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="10" name="HERO" x="120" y="56">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="11" name="STAIRS" x="104" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="14" name="SPIKES" x="136" y="72">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
BIN
examples/the-dungeon-keepers-lament/maps/ui_tiles.png
Normal file
BIN
examples/the-dungeon-keepers-lament/maps/ui_tiles.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
3
examples/the-dungeon-keepers-lament/rust-toolchain.toml
Normal file
3
examples/the-dungeon-keepers-lament/rust-toolchain.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly"
|
||||
components = ["rust-src", "clippy", "rustfmt"]
|
BIN
examples/the-dungeon-keepers-lament/sfx/bad.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/bad.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/bang.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/bang.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/bgm.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/bgm.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/door_open.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/door_open.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/place.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/place.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/select.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/select.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/slime_death.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/slime_death.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/switch_toggle1.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/switch_toggle1.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/sword_hit.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/sword_hit.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/sword_pickup.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/sword_pickup.wav
Normal file
Binary file not shown.
BIN
examples/the-dungeon-keepers-lament/sfx/wall_hit.wav
Normal file
BIN
examples/the-dungeon-keepers-lament/sfx/wall_hit.wav
Normal file
Binary file not shown.
68
examples/the-dungeon-keepers-lament/src/backgrounds.rs
Normal file
68
examples/the-dungeon-keepers-lament/src/backgrounds.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use agb::{
|
||||
display::tiled::{RegularMap, TileFormat, TileSet, TileSetting, VRamManager},
|
||||
include_background_gfx,
|
||||
};
|
||||
|
||||
include_background_gfx!(backgrounds, "1e151b",
|
||||
ui => "maps/ui_tiles.png",
|
||||
level => "maps/level.png",
|
||||
ending => "gfx/ending_page.aseprite",
|
||||
);
|
||||
|
||||
mod tilemaps {
|
||||
use super::backgrounds;
|
||||
include!(concat!(env!("OUT_DIR"), "/tilemaps.rs"));
|
||||
}
|
||||
|
||||
pub fn load_palettes(vram_manager: &mut VRamManager) {
|
||||
vram_manager.set_background_palettes(backgrounds::PALETTES);
|
||||
}
|
||||
|
||||
pub fn load_ui(map: &mut RegularMap, vram_manager: &mut VRamManager) {
|
||||
let ui_tileset = TileSet::new(backgrounds::ui.tiles, TileFormat::FourBpp);
|
||||
|
||||
for y in 0..20u16 {
|
||||
for x in 0..30u16 {
|
||||
let tile_pos = y * 30 + x;
|
||||
let tile_setting = tilemaps::UI_BACKGROUND_MAP[tile_pos as usize];
|
||||
|
||||
map.set_tile(vram_manager, (x, y).into(), &ui_tileset, tile_setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_level_background(
|
||||
map: &mut RegularMap,
|
||||
vram_manager: &mut VRamManager,
|
||||
level_number: usize,
|
||||
) {
|
||||
let level_map = &tilemaps::LEVELS_MAP[level_number];
|
||||
|
||||
let level_tileset = TileSet::new(backgrounds::level.tiles, TileFormat::FourBpp);
|
||||
|
||||
for y in 0..20u16 {
|
||||
for x in 0..22u16 {
|
||||
let tile_pos = y * 22 + x;
|
||||
let tile_setting = level_map[tile_pos as usize];
|
||||
|
||||
map.set_tile(vram_manager, (x, y).into(), &level_tileset, tile_setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_ending_page(map: &mut RegularMap, vram_manager: &mut VRamManager) {
|
||||
let ending_tileset = TileSet::new(backgrounds::ending.tiles, TileFormat::FourBpp);
|
||||
|
||||
for y in 0..20u16 {
|
||||
for x in 0..30u16 {
|
||||
let tile_pos = y * 30 + x;
|
||||
let tile_setting = TileSetting::new(
|
||||
tile_pos,
|
||||
false,
|
||||
false,
|
||||
backgrounds::ending.palette_assignments[tile_pos as usize],
|
||||
);
|
||||
map.set_tile(vram_manager, (x, y).into(), &ending_tileset, tile_setting);
|
||||
}
|
||||
}
|
||||
}
|
434
examples/the-dungeon-keepers-lament/src/game.rs
Normal file
434
examples/the-dungeon-keepers-lament/src/game.rs
Normal file
|
@ -0,0 +1,434 @@
|
|||
use agb::{
|
||||
display::{
|
||||
object::{
|
||||
OamIterator, ObjectTextRender, ObjectUnmanaged, PaletteVram, Size, SpriteLoader,
|
||||
SpriteVram, TextAlignment,
|
||||
},
|
||||
palette16::Palette16,
|
||||
tiled::{MapLoan, RegularMap, TiledMap, VRamManager},
|
||||
HEIGHT,
|
||||
},
|
||||
fixnum::Vector2D,
|
||||
input::{Button, ButtonController, Tri},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
resources::{ARROW_RIGHT, FONT},
|
||||
sfx::Sfx,
|
||||
};
|
||||
|
||||
use self::{
|
||||
game_state::{GameState, PLAY_AREA_HEIGHT, PLAY_AREA_WIDTH},
|
||||
simulation::Simulation,
|
||||
};
|
||||
|
||||
pub use simulation::Direction;
|
||||
|
||||
use core::{cell::RefCell, fmt::Write};
|
||||
|
||||
mod game_state;
|
||||
mod simulation;
|
||||
|
||||
mod numbers;
|
||||
|
||||
struct Game<'a, 'b> {
|
||||
phase: GamePhase<'a, 'b>,
|
||||
}
|
||||
|
||||
struct Lament<'a, 'b> {
|
||||
level: usize,
|
||||
writer: RefCell<ObjectTextRender<'static>>,
|
||||
background: &'a mut MapLoan<'b, RegularMap>,
|
||||
}
|
||||
|
||||
fn generate_text_palette() -> PaletteVram {
|
||||
let mut palette = [0x0; 16];
|
||||
palette[1] = 0xFF_FF;
|
||||
let palette = Palette16::new(palette);
|
||||
PaletteVram::new(&palette).unwrap()
|
||||
}
|
||||
|
||||
impl<'a, 'b> Lament<'a, 'b> {
|
||||
fn new(level: usize, background: &'a mut MapLoan<'b, RegularMap>) -> Self {
|
||||
let palette = generate_text_palette();
|
||||
|
||||
let mut writer = ObjectTextRender::new(&super::resources::FONT, Size::S16x16, palette);
|
||||
|
||||
let _ = writeln!(
|
||||
writer,
|
||||
"{}\n\n{}",
|
||||
numbers::NUMBERS[level],
|
||||
crate::level::Level::get_level(level).name
|
||||
);
|
||||
|
||||
writer.layout(
|
||||
Vector2D::new(
|
||||
PLAY_AREA_WIDTH as i32 * 16 - 32,
|
||||
PLAY_AREA_HEIGHT as i32 * 16,
|
||||
),
|
||||
TextAlignment::Center,
|
||||
0,
|
||||
);
|
||||
|
||||
Self {
|
||||
level,
|
||||
writer: RefCell::new(writer),
|
||||
background,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(self, input: &ButtonController, vram_manager: &mut VRamManager) -> GamePhase<'a, 'b> {
|
||||
{
|
||||
let mut writer = self.writer.borrow_mut();
|
||||
writer.next_letter_group();
|
||||
writer.update(Vector2D::new(16, HEIGHT / 4));
|
||||
}
|
||||
if input.is_just_pressed(Button::A) {
|
||||
GamePhase::Construction(Construction::new(self.level, self.background, vram_manager))
|
||||
} else {
|
||||
GamePhase::Lament(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, oam: &mut OamIterator) {
|
||||
self.writer.borrow_mut().commit(oam);
|
||||
}
|
||||
}
|
||||
|
||||
struct Construction<'a, 'b> {
|
||||
game: GameState,
|
||||
background: &'a mut MapLoan<'b, RegularMap>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Drop for Construction<'a, 'b> {
|
||||
fn drop(&mut self) {
|
||||
self.background.hide();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Construction<'a, 'b> {
|
||||
fn new(
|
||||
level: usize,
|
||||
background: &'a mut MapLoan<'b, RegularMap>,
|
||||
vram_manager: &mut VRamManager,
|
||||
) -> Self {
|
||||
let game = GameState::new(level);
|
||||
game.load_level_background(background, vram_manager);
|
||||
background.commit(vram_manager);
|
||||
background.show();
|
||||
Self { background, game }
|
||||
}
|
||||
|
||||
fn update(
|
||||
mut self,
|
||||
input: &ButtonController,
|
||||
sfx: &mut Sfx,
|
||||
loader: &mut SpriteLoader,
|
||||
) -> GamePhase<'a, 'b> {
|
||||
self.game.step(input, sfx);
|
||||
if input.is_just_pressed(Button::START) {
|
||||
self.game.force_place();
|
||||
GamePhase::Execute(Execute::new(self, sfx, loader))
|
||||
} else {
|
||||
GamePhase::Construction(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, oam: &mut OamIterator, loader: &mut SpriteLoader) {
|
||||
self.game.render(loader, oam);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Execute<'a, 'b> {
|
||||
fn new(construction: Construction<'a, 'b>, sfx: &mut Sfx, loader: &mut SpriteLoader) -> Self {
|
||||
Self {
|
||||
simulation: construction.game.create_simulation(sfx, loader),
|
||||
construction,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(
|
||||
mut self,
|
||||
input: &ButtonController,
|
||||
sfx: &mut Sfx,
|
||||
loader: &mut SpriteLoader,
|
||||
) -> GamePhase<'a, 'b> {
|
||||
if input.is_just_pressed(Button::START) {
|
||||
return GamePhase::Construction(self.construction);
|
||||
}
|
||||
|
||||
match self.simulation.update(loader, sfx) {
|
||||
simulation::Outcome::Continue => GamePhase::Execute(self),
|
||||
simulation::Outcome::Loss => GamePhase::Construction(self.construction),
|
||||
simulation::Outcome::Win => GamePhase::NextLevel,
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, loader: &mut SpriteLoader, oam: &mut OamIterator) {
|
||||
self.simulation.render(oam);
|
||||
self.construction
|
||||
.game
|
||||
.render_arrows(loader, oam, Some(self.simulation.current_turn()));
|
||||
}
|
||||
}
|
||||
|
||||
struct Execute<'a, 'b> {
|
||||
simulation: Simulation,
|
||||
construction: Construction<'a, 'b>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
enum GamePhase<'a, 'b> {
|
||||
#[default]
|
||||
Empty,
|
||||
Lament(Lament<'a, 'b>),
|
||||
Construction(Construction<'a, 'b>),
|
||||
Execute(Execute<'a, 'b>),
|
||||
NextLevel,
|
||||
}
|
||||
|
||||
impl GamePhase<'_, '_> {
|
||||
fn update(
|
||||
&mut self,
|
||||
input: &ButtonController,
|
||||
sfx: &mut Sfx,
|
||||
loader: &mut SpriteLoader,
|
||||
vram_manger: &mut VRamManager,
|
||||
) {
|
||||
*self = match core::mem::take(self) {
|
||||
GamePhase::Lament(lament) => lament.update(input, vram_manger),
|
||||
GamePhase::Construction(construction) => construction.update(input, sfx, loader),
|
||||
GamePhase::Execute(execute) => execute.update(input, sfx, loader),
|
||||
GamePhase::NextLevel => GamePhase::NextLevel,
|
||||
GamePhase::Empty => panic!("bad state"),
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, loader: &mut SpriteLoader, oam: &mut OamIterator) {
|
||||
match self {
|
||||
GamePhase::Empty => panic!("bad state"),
|
||||
GamePhase::Lament(lament) => lament.render(oam),
|
||||
GamePhase::Construction(construction) => construction.render(oam, loader),
|
||||
GamePhase::Execute(execute) => execute.render(loader, oam),
|
||||
GamePhase::NextLevel => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Game<'a, 'b> {
|
||||
pub fn new(level: usize, background: &'a mut MapLoan<'b, RegularMap>) -> Self {
|
||||
Self {
|
||||
phase: GamePhase::Lament(Lament::new(level, background)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
input: &ButtonController,
|
||||
sfx: &mut Sfx,
|
||||
loader: &mut SpriteLoader,
|
||||
vram_manager: &mut VRamManager,
|
||||
) -> bool {
|
||||
self.phase.update(input, sfx, loader, vram_manager);
|
||||
matches!(self.phase, GamePhase::NextLevel)
|
||||
}
|
||||
|
||||
pub fn render(&self, loader: &mut SpriteLoader, oam: &mut OamIterator) {
|
||||
self.phase.render(loader, oam)
|
||||
}
|
||||
|
||||
pub fn hide_background(&mut self) {
|
||||
match &mut self.phase {
|
||||
GamePhase::Construction(construction) => construction.background.hide(),
|
||||
GamePhase::Execute(execute) => execute.construction.background.hide(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_background(&mut self) {
|
||||
match &mut self.phase {
|
||||
GamePhase::Construction(construction) => construction.background.show(),
|
||||
GamePhase::Execute(execute) => execute.construction.background.show(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pausable<'a, 'b> {
|
||||
paused: Paused,
|
||||
menu: PauseMenu,
|
||||
game: Game<'a, 'b>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Paused {
|
||||
Paused,
|
||||
Playing,
|
||||
}
|
||||
|
||||
impl Paused {
|
||||
fn change(self) -> Paused {
|
||||
match self {
|
||||
Paused::Paused => Paused::Playing,
|
||||
Paused::Playing => Paused::Paused,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PauseSelection {
|
||||
Restart,
|
||||
LevelSelect(usize),
|
||||
}
|
||||
|
||||
enum PauseSelectionInner {
|
||||
Restart,
|
||||
LevelSelect,
|
||||
}
|
||||
|
||||
struct PauseMenu {
|
||||
option_text: RefCell<[ObjectTextRender<'static>; 2]>,
|
||||
selection: PauseSelectionInner,
|
||||
indicator_sprite: SpriteVram,
|
||||
selected_level: usize,
|
||||
maximum_level: usize,
|
||||
}
|
||||
|
||||
impl PauseMenu {
|
||||
fn text_at_position(
|
||||
text: core::fmt::Arguments,
|
||||
position: Vector2D<i32>,
|
||||
) -> ObjectTextRender<'static> {
|
||||
let mut t = ObjectTextRender::new(&FONT, Size::S32x16, generate_text_palette());
|
||||
|
||||
let _ = writeln!(t, "{}", text);
|
||||
t.layout(Vector2D::new(i32::MAX, i32::MAX), TextAlignment::Left, 0);
|
||||
t.next_line();
|
||||
t.update(position);
|
||||
t
|
||||
}
|
||||
|
||||
fn new(loader: &mut SpriteLoader, maximum_level: usize, current_level: usize) -> Self {
|
||||
PauseMenu {
|
||||
option_text: RefCell::new([
|
||||
Self::text_at_position(format_args!("Restart"), Vector2D::new(32, HEIGHT / 4)),
|
||||
Self::text_at_position(
|
||||
format_args!("Go to level: {}", current_level + 1),
|
||||
Vector2D::new(32, HEIGHT / 4 + 20),
|
||||
),
|
||||
]),
|
||||
selection: PauseSelectionInner::Restart,
|
||||
indicator_sprite: loader.get_vram_sprite(ARROW_RIGHT.sprite(0)),
|
||||
selected_level: current_level,
|
||||
maximum_level,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, input: &ButtonController) -> Option<PauseSelection> {
|
||||
if input.is_just_pressed(Button::UP) | input.is_just_pressed(Button::DOWN) {
|
||||
self.selection = match self.selection {
|
||||
PauseSelectionInner::Restart => PauseSelectionInner::LevelSelect,
|
||||
PauseSelectionInner::LevelSelect => PauseSelectionInner::Restart,
|
||||
};
|
||||
}
|
||||
|
||||
let lr = Tri::from((
|
||||
input.is_just_pressed(Button::LEFT),
|
||||
input.is_just_pressed(Button::RIGHT),
|
||||
));
|
||||
if matches!(self.selection, PauseSelectionInner::LevelSelect) && lr != Tri::Zero {
|
||||
let selected_level = self.selected_level as i32;
|
||||
let selected_level =
|
||||
(selected_level + lr as i32).rem_euclid(self.maximum_level as i32 + 1);
|
||||
self.selected_level = selected_level as usize;
|
||||
self.option_text.borrow_mut()[1] = Self::text_at_position(
|
||||
format_args!("Go to level: {}", selected_level + 1),
|
||||
Vector2D::new(32, HEIGHT / 4 + 20),
|
||||
)
|
||||
}
|
||||
|
||||
if input.is_just_pressed(Button::A) | input.is_just_pressed(Button::START) {
|
||||
Some(match self.selection {
|
||||
PauseSelectionInner::Restart => PauseSelection::Restart,
|
||||
PauseSelectionInner::LevelSelect => {
|
||||
PauseSelection::LevelSelect(self.selected_level)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, oam: &mut OamIterator) {
|
||||
for text in self.option_text.borrow_mut().iter_mut() {
|
||||
text.commit(oam);
|
||||
}
|
||||
let mut indicator = ObjectUnmanaged::new(self.indicator_sprite.clone());
|
||||
indicator.show();
|
||||
match self.selection {
|
||||
PauseSelectionInner::Restart => indicator.set_position(Vector2D::new(16, HEIGHT / 4)),
|
||||
PauseSelectionInner::LevelSelect => {
|
||||
indicator.set_position(Vector2D::new(16, HEIGHT / 4 + 20))
|
||||
}
|
||||
};
|
||||
if let Some(slot) = oam.next() {
|
||||
slot.set(&indicator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum UpdateResult {
|
||||
MenuSelection(PauseSelection),
|
||||
NextLevel,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Pausable<'a, 'b> {
|
||||
pub fn new(
|
||||
level: usize,
|
||||
maximum_level: usize,
|
||||
background: &'a mut MapLoan<'b, RegularMap>,
|
||||
loader: &mut SpriteLoader,
|
||||
) -> Self {
|
||||
Self {
|
||||
paused: Paused::Playing,
|
||||
game: Game::new(level, background),
|
||||
menu: PauseMenu::new(loader, maximum_level, level),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
input: &ButtonController,
|
||||
sfx: &mut Sfx,
|
||||
loader: &mut SpriteLoader,
|
||||
vram_manager: &mut VRamManager,
|
||||
) -> Option<UpdateResult> {
|
||||
if input.is_just_pressed(Button::SELECT)
|
||||
|| (matches!(self.paused, Paused::Paused) && input.is_just_pressed(Button::B))
|
||||
{
|
||||
self.paused = self.paused.change();
|
||||
match self.paused {
|
||||
Paused::Paused => self.game.hide_background(),
|
||||
Paused::Playing => self.game.show_background(),
|
||||
}
|
||||
}
|
||||
|
||||
if !matches!(self.paused, Paused::Paused) {
|
||||
if self.game.update(input, sfx, loader, vram_manager) {
|
||||
Some(UpdateResult::NextLevel)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
self.menu.update(input).map(UpdateResult::MenuSelection)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, loader: &mut SpriteLoader, oam: &mut OamIterator) {
|
||||
if matches!(self.paused, Paused::Paused) {
|
||||
self.menu.render(oam);
|
||||
} else {
|
||||
self.game.render(loader, oam);
|
||||
}
|
||||
}
|
||||
}
|
459
examples/the-dungeon-keepers-lament/src/game/game_state.rs
Normal file
459
examples/the-dungeon-keepers-lament/src/game/game_state.rs
Normal file
|
@ -0,0 +1,459 @@
|
|||
use agb::{
|
||||
display::{
|
||||
object::{OamIterator, ObjectUnmanaged, SpriteLoader, Tag},
|
||||
tiled::{RegularMap, VRamManager},
|
||||
},
|
||||
fixnum::Vector2D,
|
||||
input::{Button, ButtonController, Tri},
|
||||
};
|
||||
use alloc::{vec, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
level::{Item, Level},
|
||||
map::MapElement,
|
||||
resources,
|
||||
sfx::Sfx,
|
||||
};
|
||||
|
||||
use super::simulation::{Direction, Simulation};
|
||||
|
||||
pub const PLAY_AREA_WIDTH: usize = 11;
|
||||
pub const PLAY_AREA_HEIGHT: usize = 10;
|
||||
|
||||
const ITEM_AREA_WIDTH: usize = 3;
|
||||
const ITEM_AREA_HEIGHT: usize = 3;
|
||||
|
||||
const ITEM_AREA_TOP_LEFT: Vector2D<i32> = Vector2D::new(179, 96);
|
||||
const CURSOR_OFFSET: Vector2D<i32> = Vector2D::new(14, 14);
|
||||
|
||||
const ARROW_TOP_LEFT: Vector2D<i32> = Vector2D::new(175, 15);
|
||||
|
||||
pub struct GameState {
|
||||
level_number: usize,
|
||||
level: &'static Level,
|
||||
cursor_state: CursorState,
|
||||
frame: usize,
|
||||
|
||||
item_states: Vec<ItemState>,
|
||||
}
|
||||
|
||||
impl GameState {
|
||||
pub fn new(level_number: usize) -> Self {
|
||||
let level = Level::get_level(level_number);
|
||||
|
||||
let position = level
|
||||
.entities
|
||||
.iter()
|
||||
.find(|x| x.0 == Item::Hero)
|
||||
.map(|hero| hero.1.x as usize + PLAY_AREA_WIDTH * hero.1.y as usize)
|
||||
.unwrap_or(PLAY_AREA_WIDTH * PLAY_AREA_HEIGHT / 2 + PLAY_AREA_WIDTH / 2);
|
||||
|
||||
Self {
|
||||
level_number,
|
||||
level,
|
||||
cursor_state: CursorState {
|
||||
item_position: 0,
|
||||
board_position: position,
|
||||
current_place: CursorPlace::Item,
|
||||
held_item: None,
|
||||
},
|
||||
frame: 0,
|
||||
|
||||
item_states: vec![ItemState::default(); level.items.len()],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn level_text(&self) -> &str {
|
||||
self.level.name
|
||||
}
|
||||
|
||||
pub fn create_simulation(&self, sfx: &mut Sfx, loader: &mut SpriteLoader) -> Simulation {
|
||||
Simulation::generate(
|
||||
self.item_states
|
||||
.iter()
|
||||
.zip(self.level.items)
|
||||
.filter_map(|(location, item)| match location {
|
||||
ItemState::Placed(loc) => Some((*loc, *item)),
|
||||
ItemState::NotPlaced => None,
|
||||
})
|
||||
.map(|(location, item)| {
|
||||
(
|
||||
item,
|
||||
Vector2D::new(
|
||||
(location % PLAY_AREA_WIDTH) as i32,
|
||||
(location / PLAY_AREA_WIDTH) as i32,
|
||||
),
|
||||
)
|
||||
})
|
||||
.chain(self.level.entities.iter().map(|x| (x.0, x.1))),
|
||||
self.level,
|
||||
sfx,
|
||||
loader,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn load_level_background(&self, map: &mut RegularMap, vram_manager: &mut VRamManager) {
|
||||
crate::backgrounds::load_level_background(map, vram_manager, self.level_number);
|
||||
}
|
||||
|
||||
pub fn force_place(&mut self) {
|
||||
if self.cursor_state.current_place == CursorPlace::Board {
|
||||
let position_x = (self.cursor_state.board_position % PLAY_AREA_WIDTH) as i32;
|
||||
let position_y = (self.cursor_state.board_position / PLAY_AREA_WIDTH) as i32;
|
||||
|
||||
let position: Vector2D<_> = (position_x, position_y).into();
|
||||
|
||||
let map_tile = self.level.map[(position_x, position_y)];
|
||||
|
||||
let fixed_item_at_location = self
|
||||
.level
|
||||
.entities
|
||||
.iter()
|
||||
.any(|entity| entity.1 == position);
|
||||
|
||||
if map_tile == MapElement::Floor && !fixed_item_at_location {
|
||||
let placeable_item_at_location =
|
||||
self.item_states.iter().position(|state| match state {
|
||||
ItemState::Placed(position) => {
|
||||
*position == self.cursor_state.board_position
|
||||
}
|
||||
ItemState::NotPlaced => false,
|
||||
});
|
||||
|
||||
if placeable_item_at_location.is_none() {
|
||||
if let Some(held_item) = self.cursor_state.held_item {
|
||||
self.item_states[held_item] =
|
||||
ItemState::Placed(self.cursor_state.board_position);
|
||||
self.cursor_state.held_item = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step(&mut self, input: &ButtonController, sfx: &mut Sfx) {
|
||||
self.frame = self.frame.wrapping_add(1);
|
||||
|
||||
self.cursor_state.update_position(input);
|
||||
|
||||
if input.is_just_pressed(Button::A) {
|
||||
match self.cursor_state.current_place {
|
||||
CursorPlace::Board => {
|
||||
let position_x = (self.cursor_state.board_position % PLAY_AREA_WIDTH) as i32;
|
||||
let position_y = (self.cursor_state.board_position / PLAY_AREA_WIDTH) as i32;
|
||||
|
||||
let position: Vector2D<_> = (position_x, position_y).into();
|
||||
|
||||
let map_tile = self.level.map[(position_x, position_y)];
|
||||
|
||||
let fixed_item_at_location = self
|
||||
.level
|
||||
.entities
|
||||
.iter()
|
||||
.any(|entity| entity.1 == position);
|
||||
|
||||
if map_tile == MapElement::Floor && !fixed_item_at_location {
|
||||
let placeable_item_at_location =
|
||||
self.item_states.iter().position(|state| match state {
|
||||
ItemState::Placed(position) => {
|
||||
*position == self.cursor_state.board_position
|
||||
}
|
||||
ItemState::NotPlaced => false,
|
||||
});
|
||||
|
||||
let played_sound = if let Some(held_item) = self.cursor_state.held_item {
|
||||
self.item_states[held_item] =
|
||||
ItemState::Placed(self.cursor_state.board_position);
|
||||
self.cursor_state.held_item = None;
|
||||
|
||||
sfx.place();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if let Some(placeable_item_at_location) = placeable_item_at_location {
|
||||
self.cursor_state.held_item = Some(placeable_item_at_location);
|
||||
self.item_states[placeable_item_at_location] = ItemState::NotPlaced;
|
||||
|
||||
if !played_sound {
|
||||
sfx.select();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sfx.bad_selection();
|
||||
}
|
||||
}
|
||||
CursorPlace::Item => {
|
||||
let item_position = self.cursor_state.item_position;
|
||||
|
||||
if matches!(
|
||||
self.item_states.get(item_position),
|
||||
Some(ItemState::NotPlaced)
|
||||
) {
|
||||
sfx.select();
|
||||
self.cursor_state.current_place = CursorPlace::Board;
|
||||
self.cursor_state.held_item = Some(item_position);
|
||||
} else {
|
||||
sfx.bad_selection();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if input.is_just_pressed(Button::B) {
|
||||
match self.cursor_state.current_place {
|
||||
CursorPlace::Item => {
|
||||
self.cursor_state.current_place = CursorPlace::Board;
|
||||
self.cursor_state.held_item = None;
|
||||
}
|
||||
CursorPlace::Board => {
|
||||
self.cursor_state.current_place = CursorPlace::Item;
|
||||
self.cursor_state.held_item = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_arrows(
|
||||
&self,
|
||||
loader: &mut SpriteLoader,
|
||||
oam: &mut OamIterator,
|
||||
current_turn: Option<usize>,
|
||||
) {
|
||||
let is_odd_frame = if current_turn.is_some() {
|
||||
true
|
||||
} else {
|
||||
let frame_index = self.frame / 32;
|
||||
frame_index % 2 == 1
|
||||
};
|
||||
|
||||
for ((i, direction), slot) in self.level.directions.iter().enumerate().zip(oam) {
|
||||
let x = (i % 4) as i32;
|
||||
let y = (i / 4) as i32;
|
||||
|
||||
let arrow_position = ARROW_TOP_LEFT + (x * 15, y * 15).into();
|
||||
let arrow_position = if is_odd_frame {
|
||||
arrow_odd_frame_offset(*direction)
|
||||
} else {
|
||||
(0, 0).into()
|
||||
} + arrow_position;
|
||||
|
||||
let sprite_idx = if Some(i) == current_turn { 1 } else { 0 };
|
||||
|
||||
let mut arrow_obj = ObjectUnmanaged::new(
|
||||
loader.get_vram_sprite(arrow_for_direction(*direction).sprite(sprite_idx)),
|
||||
);
|
||||
arrow_obj.show().set_position(arrow_position);
|
||||
|
||||
slot.set(&arrow_obj);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, loader: &mut SpriteLoader, mut oam: &mut OamIterator) {
|
||||
let frame_index = self.frame / 32;
|
||||
let is_odd_frame = frame_index % 2 == 1;
|
||||
|
||||
let mut cursor_obj =
|
||||
ObjectUnmanaged::new(loader.get_vram_sprite(resources::CURSOR.sprite(0)));
|
||||
cursor_obj
|
||||
.show()
|
||||
.set_position(self.cursor_state.get_position(is_odd_frame));
|
||||
|
||||
if let Some(slot) = oam.next() {
|
||||
slot.set(&cursor_obj);
|
||||
}
|
||||
|
||||
let level = self.level;
|
||||
|
||||
self.render_arrows(loader, oam, None);
|
||||
|
||||
fn placed_position(position: usize, item: &Item) -> Vector2D<i32> {
|
||||
let position_x = (position % PLAY_AREA_WIDTH) as i32;
|
||||
let position_y = (position / PLAY_AREA_WIDTH) as i32;
|
||||
let position = Vector2D::new(position_x, position_y);
|
||||
|
||||
position * 16 + item.map_entity_offset()
|
||||
}
|
||||
|
||||
if let Some(held) = self.cursor_state.held_item {
|
||||
let item = &level.items[held];
|
||||
let item_position = placed_position(self.cursor_state.board_position, item);
|
||||
let mut item_obj = ObjectUnmanaged::new(
|
||||
loader.get_vram_sprite(item.tag().animation_sprite(frame_index)),
|
||||
);
|
||||
item_obj.show().set_position(item_position);
|
||||
|
||||
if let Some(slot) = oam.next() {
|
||||
slot.set(&item_obj);
|
||||
}
|
||||
}
|
||||
|
||||
for ((item_position, item), slot) in level
|
||||
.items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, item)| {
|
||||
let item_position = match self.item_states[i] {
|
||||
ItemState::Placed(position) => placed_position(position, item),
|
||||
ItemState::NotPlaced => {
|
||||
if self.cursor_state.held_item == Some(i) {
|
||||
return None;
|
||||
} else {
|
||||
let x = (i % ITEM_AREA_WIDTH) as i32;
|
||||
let y = (i / ITEM_AREA_WIDTH) as i32;
|
||||
|
||||
ITEM_AREA_TOP_LEFT + (x * 16, y * 16).into()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some((item_position, item))
|
||||
})
|
||||
.zip(&mut oam)
|
||||
{
|
||||
let mut item_obj = ObjectUnmanaged::new(
|
||||
loader.get_vram_sprite(item.tag().animation_sprite(frame_index)),
|
||||
);
|
||||
item_obj.show().set_position(item_position);
|
||||
|
||||
slot.set(&item_obj);
|
||||
}
|
||||
|
||||
for (entity, slot) in level.entities.iter().zip(&mut oam) {
|
||||
let entity_position = entity.1 * 16 + entity.0.map_entity_offset();
|
||||
|
||||
let mut entity_obj =
|
||||
ObjectUnmanaged::new(loader.get_vram_sprite(entity.0.shadow_tag().sprite(0)));
|
||||
entity_obj.show().set_position(entity_position);
|
||||
|
||||
slot.set(&entity_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CursorState {
|
||||
item_position: usize,
|
||||
board_position: usize,
|
||||
current_place: CursorPlace,
|
||||
held_item: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
enum CursorPlace {
|
||||
Item,
|
||||
Board,
|
||||
}
|
||||
|
||||
impl CursorState {
|
||||
fn get_position(&self, is_odd_frame: bool) -> Vector2D<i32> {
|
||||
let odd_frame_offset = if is_odd_frame {
|
||||
Vector2D::new(1, 1)
|
||||
} else {
|
||||
Vector2D::new(0, 0)
|
||||
};
|
||||
let place_position: Vector2D<_> = match self.current_place {
|
||||
CursorPlace::Board => {
|
||||
let current_x = (self.board_position % PLAY_AREA_WIDTH) as i32;
|
||||
let current_y = (self.board_position / PLAY_AREA_WIDTH) as i32;
|
||||
|
||||
(current_x * 16, current_y * 16).into()
|
||||
}
|
||||
CursorPlace::Item => {
|
||||
let current_x = (self.item_position % ITEM_AREA_WIDTH) as i32;
|
||||
let current_y = (self.item_position / ITEM_AREA_WIDTH) as i32;
|
||||
|
||||
ITEM_AREA_TOP_LEFT + (current_x * 16, current_y * 16).into()
|
||||
}
|
||||
};
|
||||
|
||||
place_position + CURSOR_OFFSET + odd_frame_offset
|
||||
}
|
||||
|
||||
fn update_position(&mut self, input: &ButtonController) {
|
||||
let ud: Tri = (
|
||||
input.is_just_pressed(Button::UP),
|
||||
input.is_just_pressed(Button::DOWN),
|
||||
)
|
||||
.into();
|
||||
let lr: Tri = (
|
||||
input.is_just_pressed(Button::LEFT),
|
||||
input.is_just_pressed(Button::RIGHT),
|
||||
)
|
||||
.into();
|
||||
|
||||
if ud == Tri::Zero && lr == Tri::Zero {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.current_place {
|
||||
CursorPlace::Board => {
|
||||
let current_x = self.board_position % PLAY_AREA_WIDTH;
|
||||
let current_y = self.board_position / PLAY_AREA_WIDTH;
|
||||
|
||||
let mut new_x = current_x.saturating_add_signed(lr as isize).max(1);
|
||||
let new_y = current_y
|
||||
.saturating_add_signed(ud as isize)
|
||||
.max(1)
|
||||
.min(PLAY_AREA_HEIGHT - 2);
|
||||
|
||||
if new_x == PLAY_AREA_WIDTH - 1 {
|
||||
new_x = new_x.min(PLAY_AREA_WIDTH - 2);
|
||||
|
||||
if self.held_item.is_none() {
|
||||
self.current_place = CursorPlace::Item;
|
||||
self.item_position = new_y.saturating_sub(5).clamp(0, ITEM_AREA_HEIGHT - 1)
|
||||
* ITEM_AREA_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
self.board_position = new_x + new_y * PLAY_AREA_WIDTH;
|
||||
}
|
||||
CursorPlace::Item => {
|
||||
let current_x = self.item_position % ITEM_AREA_WIDTH;
|
||||
let current_y = self.item_position / ITEM_AREA_WIDTH;
|
||||
|
||||
let mut new_x = current_x.wrapping_add_signed(lr as isize);
|
||||
let new_y = current_y
|
||||
.saturating_add_signed(ud as isize)
|
||||
.min(ITEM_AREA_HEIGHT - 1);
|
||||
|
||||
if new_x == usize::MAX {
|
||||
new_x = 0;
|
||||
|
||||
self.current_place = CursorPlace::Board;
|
||||
self.board_position = (new_y + 5) * PLAY_AREA_WIDTH + PLAY_AREA_WIDTH - 2;
|
||||
} else {
|
||||
new_x = new_x.min(ITEM_AREA_WIDTH - 1);
|
||||
}
|
||||
|
||||
self.item_position = new_x + new_y * ITEM_AREA_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn arrow_for_direction(direction: Direction) -> &'static Tag {
|
||||
match direction {
|
||||
Direction::Up => resources::ARROW_UP,
|
||||
Direction::Down => resources::ARROW_DOWN,
|
||||
Direction::Left => resources::ARROW_LEFT,
|
||||
Direction::Right => resources::ARROW_RIGHT,
|
||||
}
|
||||
}
|
||||
|
||||
const fn arrow_odd_frame_offset(direction: Direction) -> Vector2D<i32> {
|
||||
match direction {
|
||||
Direction::Up => Vector2D::new(0, -1),
|
||||
Direction::Down => Vector2D::new(0, 1),
|
||||
Direction::Left => Vector2D::new(-1, 0),
|
||||
Direction::Right => Vector2D::new(1, 0),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
enum ItemState {
|
||||
Placed(usize),
|
||||
#[default]
|
||||
NotPlaced,
|
||||
}
|
22
examples/the-dungeon-keepers-lament/src/game/numbers.rs
Normal file
22
examples/the-dungeon-keepers-lament/src/game/numbers.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
pub const NUMBERS: &[&str] = &[
|
||||
"One",
|
||||
"Two",
|
||||
"Three",
|
||||
"Four",
|
||||
"Five",
|
||||
"Six",
|
||||
"Seven",
|
||||
"Eight",
|
||||
"Nine",
|
||||
"Ten",
|
||||
"Eleven",
|
||||
"Twelve",
|
||||
"Thirteen",
|
||||
"Fourteen",
|
||||
"Fifteen",
|
||||
"Sixteen",
|
||||
"Seventeen",
|
||||
"Eighteen",
|
||||
"Ninteen",
|
||||
"Twenty",
|
||||
];
|
109
examples/the-dungeon-keepers-lament/src/game/simulation.rs
Normal file
109
examples/the-dungeon-keepers-lament/src/game/simulation.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
use agb::{
|
||||
display::object::{OamIterator, SpriteLoader},
|
||||
fixnum::{Num, Vector2D},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
level::{Item, Level},
|
||||
sfx::Sfx,
|
||||
};
|
||||
|
||||
use self::{
|
||||
animation::{Animation, RenderCache},
|
||||
entity::{Action, EntityMap},
|
||||
};
|
||||
|
||||
mod animation;
|
||||
mod entity;
|
||||
|
||||
pub use entity::Direction;
|
||||
pub use entity::Outcome;
|
||||
|
||||
pub struct Simulation {
|
||||
entities: EntityMap,
|
||||
animation: Animation,
|
||||
level: &'static Level,
|
||||
move_idx: usize,
|
||||
outcome: Outcome,
|
||||
frame: usize,
|
||||
|
||||
render_cache: Vec<RenderCache>,
|
||||
}
|
||||
|
||||
impl Simulation {
|
||||
pub fn generate(
|
||||
a: impl Iterator<Item = (Item, Vector2D<i32>)>,
|
||||
level: &'static Level,
|
||||
sfx: &mut Sfx,
|
||||
loader: &mut SpriteLoader,
|
||||
) -> Simulation {
|
||||
let mut entities = EntityMap::default();
|
||||
let mut animation = Animation::default();
|
||||
|
||||
for (item, location) in a {
|
||||
animation.populate(entities.add(item, location), sfx);
|
||||
}
|
||||
|
||||
let mut simulation = Simulation {
|
||||
entities,
|
||||
animation,
|
||||
move_idx: 0,
|
||||
level,
|
||||
outcome: Outcome::Continue,
|
||||
frame: 0,
|
||||
render_cache: Vec::new(),
|
||||
};
|
||||
|
||||
simulation.cache_render(loader);
|
||||
|
||||
simulation
|
||||
}
|
||||
|
||||
pub fn current_turn(&self) -> usize {
|
||||
self.move_idx.saturating_sub(1)
|
||||
}
|
||||
|
||||
pub fn render(&self, oam: &mut OamIterator) {
|
||||
for item in self.render_cache.iter() {
|
||||
item.render(oam);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cache_render(&mut self, sprite_loader: &mut SpriteLoader) {
|
||||
self.render_cache = self.animation.cache_render(sprite_loader, self.frame / 16);
|
||||
self.render_cache
|
||||
.sort_unstable_by_key(|x| x.sorting_number());
|
||||
}
|
||||
|
||||
pub fn update(&mut self, sprite_loader: &mut SpriteLoader, sfx: &mut Sfx) -> Outcome {
|
||||
self.animation.increase_progress(Num::new(1) / 16);
|
||||
|
||||
self.frame = self.frame.wrapping_add(1);
|
||||
|
||||
let animation_result = self.animation.update(sfx);
|
||||
|
||||
self.cache_render(sprite_loader);
|
||||
|
||||
if animation_result {
|
||||
if self.outcome != Outcome::Continue {
|
||||
return self.outcome;
|
||||
}
|
||||
let hero_move = self.level.directions.get(self.move_idx);
|
||||
if let Some(&hero_move) = hero_move {
|
||||
let (outcome, animation) = self
|
||||
.entities
|
||||
.tick(&self.level.map, Action::Direction(hero_move));
|
||||
self.move_idx += 1;
|
||||
self.outcome = outcome;
|
||||
for anim in animation {
|
||||
self.animation.populate(anim, sfx);
|
||||
}
|
||||
} else {
|
||||
return Outcome::Loss;
|
||||
}
|
||||
}
|
||||
|
||||
Outcome::Continue
|
||||
}
|
||||
}
|
|
@ -0,0 +1,406 @@
|
|||
#![deny(clippy::indexing_slicing)]
|
||||
#![deny(clippy::panicking_unwrap)]
|
||||
#![deny(clippy::panic_in_result_fn)]
|
||||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use agb::{
|
||||
display::object::{OamIterator, ObjectUnmanaged, SpriteLoader},
|
||||
fixnum::{Num, Vector2D},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use slotmap::SecondaryMap;
|
||||
|
||||
use crate::{
|
||||
level::Item,
|
||||
resources::HERO_CARRY,
|
||||
sfx::{Sfx, SoundEffect},
|
||||
};
|
||||
|
||||
use super::entity::{Direction, EntityKey};
|
||||
|
||||
struct AnimationEntity {
|
||||
entity: Item,
|
||||
start_position: Vector2D<Num<i32, 10>>,
|
||||
rendered_position: Vector2D<Num<i32, 10>>,
|
||||
attached: Option<(Item, Num<i32, 10>)>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ToPlay {
|
||||
moves: Vec<Move>,
|
||||
attach_progress: Vec<AttachProgress>,
|
||||
fakeout: Vec<FakeOutMove>,
|
||||
detatch: Vec<Detatch>,
|
||||
attach: Vec<Attach>,
|
||||
change: Vec<Change>,
|
||||
die: Vec<Die>,
|
||||
}
|
||||
|
||||
fn convert_to_real_space(p: Vector2D<i32>) -> Vector2D<Num<i32, 10>> {
|
||||
p.change_base() * 16
|
||||
}
|
||||
|
||||
impl ToPlay {
|
||||
pub fn populate(
|
||||
&mut self,
|
||||
instruction: AnimationInstruction,
|
||||
map: &mut SecondaryMap<EntityKey, AnimationEntity>,
|
||||
sfx: &mut Sfx<'_>,
|
||||
) {
|
||||
match instruction {
|
||||
AnimationInstruction::Move(e, p, s) => {
|
||||
self.moves.push(Move(e, convert_to_real_space(p), s));
|
||||
}
|
||||
AnimationInstruction::FakeOutMove(e, d, s) => self.fakeout.push(FakeOutMove(e, d, s)),
|
||||
AnimationInstruction::Detatch(e, nk, s) => self.detatch.push(Detatch(e, nk, s)),
|
||||
AnimationInstruction::Attach(e, o, s) => {
|
||||
if let Some(entity_to_attach) = map.get(o) {
|
||||
self.attach.push(Attach(e, entity_to_attach.entity, o, s))
|
||||
}
|
||||
}
|
||||
AnimationInstruction::Die(e, s) => self.die.push(Die(e, s)),
|
||||
AnimationInstruction::Add(e, item, p, s) => {
|
||||
map.insert(
|
||||
e,
|
||||
AnimationEntity {
|
||||
entity: item,
|
||||
start_position: convert_to_real_space(p),
|
||||
rendered_position: convert_to_real_space(p),
|
||||
attached: None,
|
||||
},
|
||||
);
|
||||
sfx.play_sound_effect(s);
|
||||
}
|
||||
AnimationInstruction::Change(e, i, s) => self.change.push(Change(e, i, s)),
|
||||
AnimationInstruction::PriorityChange(e, i, s) => {
|
||||
if let Some(entity) = map.get_mut(e) {
|
||||
entity.entity = i;
|
||||
sfx.play_sound_effect(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Animation {
|
||||
map: Map,
|
||||
to_play: ToPlay,
|
||||
ease: Num<i32, 10>,
|
||||
time: Num<i32, 10>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Map {
|
||||
map: SecondaryMap<EntityKey, AnimationEntity>,
|
||||
}
|
||||
|
||||
fn attached_offset() -> Vector2D<Num<i32, 10>> {
|
||||
Vector2D::new(0, -10).change_base()
|
||||
}
|
||||
|
||||
pub struct RenderCache {
|
||||
y: i32,
|
||||
item: Item,
|
||||
held: bool,
|
||||
object: ObjectUnmanaged,
|
||||
}
|
||||
|
||||
impl RenderCache {
|
||||
pub fn render(&self, oam: &mut OamIterator) {
|
||||
if let Some(slot) = oam.next() {
|
||||
slot.set(&self.object);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sorting_number(&self) -> i32 {
|
||||
let mut score = 0;
|
||||
if matches!(
|
||||
self.item,
|
||||
Item::Stairs | Item::Switch | Item::SwitchPressed | Item::SpikesDown | Item::SpikesUp
|
||||
) {
|
||||
score += 100000;
|
||||
}
|
||||
|
||||
if self.held {
|
||||
score -= 10000;
|
||||
}
|
||||
|
||||
if matches!(self.item, Item::Hero) {
|
||||
score -= 1000;
|
||||
}
|
||||
|
||||
score -= self.y;
|
||||
|
||||
score
|
||||
}
|
||||
}
|
||||
|
||||
impl Map {
|
||||
fn set_entity_start_location(
|
||||
&mut self,
|
||||
entity: EntityKey,
|
||||
destination: Vector2D<Num<i32, 10>>,
|
||||
) {
|
||||
if let Some(entity) = self.map.get_mut(entity) {
|
||||
entity.rendered_position = destination;
|
||||
entity.start_position = destination;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_entity_to_start_location(&mut self, entity: EntityKey) {
|
||||
if let Some(entity) = self.map.get_mut(entity) {
|
||||
entity.rendered_position = entity.start_position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Map {
|
||||
type Target = SecondaryMap<EntityKey, AnimationEntity>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.map
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Map {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.map
|
||||
}
|
||||
}
|
||||
|
||||
impl Animation {
|
||||
pub fn populate(&mut self, instruction: AnimationInstruction, sfx: &mut Sfx) {
|
||||
self.to_play.populate(instruction, &mut self.map, sfx);
|
||||
}
|
||||
|
||||
pub fn increase_progress(&mut self, amount_by: Num<i32, 10>) {
|
||||
self.time += amount_by;
|
||||
if self.time >= 1.into() {
|
||||
self.time = 1.into();
|
||||
}
|
||||
|
||||
let ease_in = self.time;
|
||||
let sub = self.time - 1;
|
||||
let ease_out = -sub * sub + 1;
|
||||
self.ease = ease_in * (Num::new(1) - self.time) + ease_out * self.time;
|
||||
}
|
||||
|
||||
pub fn cache_render(
|
||||
&self,
|
||||
sprite_loader: &mut SpriteLoader,
|
||||
animation_frame: usize,
|
||||
) -> Vec<RenderCache> {
|
||||
let mut cache = Vec::new();
|
||||
|
||||
for (_, entity) in self.map.iter() {
|
||||
if let Some((attached, attach_progress)) = entity.attached {
|
||||
let mut object = ObjectUnmanaged::new(
|
||||
sprite_loader.get_vram_sprite(attached.tag().animation_sprite(animation_frame)),
|
||||
);
|
||||
|
||||
let pos = (entity.rendered_position + attached_offset() * attach_progress).floor()
|
||||
+ attached.map_entity_offset();
|
||||
object.show().set_position(pos);
|
||||
|
||||
cache.push(RenderCache {
|
||||
object,
|
||||
y: pos.y,
|
||||
held: true,
|
||||
item: attached,
|
||||
});
|
||||
}
|
||||
|
||||
let sprite = if entity.entity == Item::Hero && entity.attached.is_some() {
|
||||
HERO_CARRY.animation_sprite(animation_frame)
|
||||
} else {
|
||||
entity.entity.shadow_tag().animation_sprite(animation_frame)
|
||||
};
|
||||
|
||||
let mut object = ObjectUnmanaged::new(sprite_loader.get_vram_sprite(sprite));
|
||||
let position = entity.rendered_position.floor() + entity.entity.map_entity_offset();
|
||||
object.show().set_position(position);
|
||||
|
||||
cache.push(RenderCache {
|
||||
object,
|
||||
y: position.y,
|
||||
held: false,
|
||||
item: entity.entity,
|
||||
});
|
||||
}
|
||||
|
||||
cache
|
||||
}
|
||||
|
||||
pub fn update(&mut self, sfx: &mut Sfx) -> bool {
|
||||
if !self.to_play.moves.is_empty()
|
||||
|| !self.to_play.fakeout.is_empty()
|
||||
|| !self.to_play.attach_progress.is_empty()
|
||||
{
|
||||
if self.time >= 1.into() {
|
||||
// finalise animations
|
||||
for m in self.to_play.moves.drain(0..) {
|
||||
let entity = m.0;
|
||||
let destination = m.1;
|
||||
|
||||
self.map.set_entity_start_location(entity, destination);
|
||||
}
|
||||
|
||||
for m in self.to_play.fakeout.drain(0..) {
|
||||
let entity = m.0;
|
||||
|
||||
self.map.set_entity_to_start_location(entity);
|
||||
}
|
||||
|
||||
for m in self.to_play.attach_progress.drain(0..) {
|
||||
if let Some(ease) = self
|
||||
.map
|
||||
.get_mut(m.0)
|
||||
.and_then(|x| x.attached.as_mut())
|
||||
.map(|x| &mut x.1)
|
||||
{
|
||||
*ease = 1.into();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// play moves and fakeouts
|
||||
for m in self.to_play.moves.iter_mut() {
|
||||
let entity = m.0;
|
||||
let destination = m.1;
|
||||
|
||||
sfx.play_sound_effect(m.2.take());
|
||||
|
||||
if let Some(entity) = self.map.get_mut(entity) {
|
||||
let location = entity.start_position * (Num::<i32, 10>::new(1) - self.ease)
|
||||
+ destination * self.ease;
|
||||
|
||||
entity.rendered_position = location;
|
||||
}
|
||||
}
|
||||
|
||||
for m in self.to_play.fakeout.iter_mut() {
|
||||
let entity = m.0;
|
||||
let direction = m.1;
|
||||
let direction = convert_to_real_space(direction.into());
|
||||
|
||||
sfx.play_sound_effect(m.2.take());
|
||||
|
||||
let go_to = direction / 2;
|
||||
|
||||
let start = (self.ease * 2 - 1).abs();
|
||||
let end_multiplier = -start + 1;
|
||||
|
||||
if let Some(entity) = self.map.get_mut(entity) {
|
||||
let location = entity.start_position + go_to * end_multiplier;
|
||||
|
||||
entity.rendered_position = location;
|
||||
}
|
||||
}
|
||||
|
||||
for m in self.to_play.attach_progress.iter_mut() {
|
||||
sfx.play_sound_effect(m.1.take());
|
||||
if let Some(ease) = self
|
||||
.map
|
||||
.get_mut(m.0)
|
||||
.and_then(|x| x.attached.as_mut())
|
||||
.map(|x| &mut x.1)
|
||||
{
|
||||
*ease = self.ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if !self.to_play.detatch.is_empty() {
|
||||
self.time = 0.into();
|
||||
for detatch in self.to_play.detatch.drain(0..) {
|
||||
let entity = detatch.0;
|
||||
let new_key = detatch.1;
|
||||
|
||||
sfx.play_sound_effect(detatch.2);
|
||||
|
||||
if let Some((entity, attached)) = self
|
||||
.map
|
||||
.get_mut(entity)
|
||||
.and_then(|x| x.attached.take().map(|y| (x, y)))
|
||||
{
|
||||
let position = entity.start_position + attached_offset();
|
||||
let destination_position = entity.start_position;
|
||||
self.map.insert(
|
||||
new_key,
|
||||
AnimationEntity {
|
||||
entity: attached.0,
|
||||
start_position: position,
|
||||
rendered_position: position,
|
||||
attached: None,
|
||||
},
|
||||
);
|
||||
self.to_play
|
||||
.moves
|
||||
.push(Move(new_key, destination_position, None));
|
||||
}
|
||||
}
|
||||
} else if !self.to_play.attach.is_empty() {
|
||||
self.time = 0.into();
|
||||
for attach in self.to_play.attach.drain(0..) {
|
||||
let entity_to_attach_to = attach.0;
|
||||
let other = attach.1;
|
||||
|
||||
sfx.play_sound_effect(attach.3);
|
||||
|
||||
if let Some(entity) = self.map.get_mut(entity_to_attach_to) {
|
||||
entity.attached = Some((other, 0.into()));
|
||||
}
|
||||
|
||||
self.map.remove(attach.2);
|
||||
self.to_play
|
||||
.attach_progress
|
||||
.push(AttachProgress(entity_to_attach_to, None));
|
||||
}
|
||||
} else if !self.to_play.change.is_empty() {
|
||||
self.time = 0.into();
|
||||
for change in self.to_play.change.drain(0..) {
|
||||
let entity = change.0;
|
||||
let item = change.1;
|
||||
|
||||
sfx.play_sound_effect(change.2);
|
||||
|
||||
if let Some(entity) = self.map.get_mut(entity) {
|
||||
entity.entity = item;
|
||||
}
|
||||
}
|
||||
} else if !self.to_play.die.is_empty() {
|
||||
self.time = 0.into();
|
||||
for death in self.to_play.die.drain(0..) {
|
||||
sfx.play_sound_effect(death.1);
|
||||
|
||||
let to_die = death.0;
|
||||
self.map.remove(to_die);
|
||||
}
|
||||
} else {
|
||||
self.time = 0.into();
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct Move(EntityKey, Vector2D<Num<i32, 10>>, Option<SoundEffect>);
|
||||
struct FakeOutMove(EntityKey, Direction, Option<SoundEffect>);
|
||||
struct Detatch(EntityKey, EntityKey, Option<SoundEffect>);
|
||||
struct Attach(EntityKey, Item, EntityKey, Option<SoundEffect>);
|
||||
struct AttachProgress(EntityKey, Option<SoundEffect>);
|
||||
struct Die(EntityKey, Option<SoundEffect>);
|
||||
struct Change(EntityKey, Item, Option<SoundEffect>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AnimationInstruction {
|
||||
Add(EntityKey, Item, Vector2D<i32>, Option<SoundEffect>),
|
||||
Move(EntityKey, Vector2D<i32>, Option<SoundEffect>),
|
||||
FakeOutMove(EntityKey, Direction, Option<SoundEffect>),
|
||||
Detatch(EntityKey, EntityKey, Option<SoundEffect>),
|
||||
Attach(EntityKey, EntityKey, Option<SoundEffect>),
|
||||
Change(EntityKey, Item, Option<SoundEffect>),
|
||||
PriorityChange(EntityKey, Item, Option<SoundEffect>),
|
||||
Die(EntityKey, Option<SoundEffect>),
|
||||
}
|
|
@ -0,0 +1,718 @@
|
|||
#![deny(clippy::indexing_slicing)]
|
||||
#![deny(clippy::panicking_unwrap)]
|
||||
#![deny(clippy::panic_in_result_fn)]
|
||||
|
||||
use core::ops::Neg;
|
||||
|
||||
use agb::fixnum::Vector2D;
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use slotmap::{new_key_type, SlotMap};
|
||||
|
||||
use crate::{
|
||||
level::{self},
|
||||
map::{Map, MapElement},
|
||||
sfx::SoundEffect,
|
||||
};
|
||||
|
||||
use super::animation::AnimationInstruction;
|
||||
|
||||
new_key_type! { pub struct EntityKey; }
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EntityMap {
|
||||
map: SlotMap<EntityKey, Entity>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||
pub enum Outcome {
|
||||
Continue,
|
||||
Loss,
|
||||
Win,
|
||||
}
|
||||
|
||||
impl EntityMap {
|
||||
fn whats_at(&self, location: Vector2D<i32>) -> impl Iterator<Item = (EntityKey, &Entity)> {
|
||||
self.map
|
||||
.iter()
|
||||
.filter(move |(_, entity)| entity.location == location)
|
||||
}
|
||||
|
||||
// returns whether killing this is a loss
|
||||
fn kill_entity(
|
||||
&mut self,
|
||||
entity: EntityKey,
|
||||
animations: &mut Vec<AnimationInstruction>,
|
||||
) -> bool {
|
||||
if let Some((location, holding)) = self
|
||||
.map
|
||||
.get_mut(entity)
|
||||
.and_then(|x| x.take_holding().map(|y| (x.location, y)))
|
||||
{
|
||||
let new_key = self.map.insert(Entity {
|
||||
location,
|
||||
entity: holding,
|
||||
});
|
||||
|
||||
animations.push(AnimationInstruction::Detatch(
|
||||
entity,
|
||||
new_key,
|
||||
self.map.get(new_key).and_then(|e| e.drop_effect()),
|
||||
));
|
||||
}
|
||||
|
||||
animations.push(AnimationInstruction::Die(
|
||||
entity,
|
||||
self.map.get(entity).and_then(|e| e.die_effect()),
|
||||
));
|
||||
|
||||
if let Some(entity) = self.map.remove(entity) {
|
||||
matches!(entity.entity, EntityType::Hero(_))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(
|
||||
&mut self,
|
||||
entity: crate::level::Item,
|
||||
location: Vector2D<i32>,
|
||||
) -> AnimationInstruction {
|
||||
let idx = self.map.insert(Entity {
|
||||
location,
|
||||
entity: entity.into(),
|
||||
});
|
||||
|
||||
AnimationInstruction::Add(idx, entity, location, None)
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, map: &Map, hero: Action) -> (Outcome, Vec<AnimationInstruction>) {
|
||||
let mut hero_has_died = false;
|
||||
let mut win_has_triggered = false;
|
||||
|
||||
let mut animations = Vec::new();
|
||||
|
||||
let desired_actions: Vec<(EntityKey, Action)> = self
|
||||
.map
|
||||
.iter()
|
||||
.map(|(key, entity)| (key, entity.desired_action(map, self, hero)))
|
||||
.collect();
|
||||
|
||||
for (entity_key, action) in desired_actions {
|
||||
if !self.map.contains_key(entity_key) {
|
||||
continue;
|
||||
}
|
||||
match action {
|
||||
Action::Nothing => {
|
||||
// nothing does nothing and causes nothing to happen
|
||||
}
|
||||
|
||||
Action::Direction(direction) | Action::ChangeDirection(direction) => {
|
||||
if matches!(action, Action::ChangeDirection(_)) {
|
||||
if let Some(change) = self
|
||||
.map
|
||||
.get_mut(entity_key)
|
||||
.and_then(|e| e.change_direction())
|
||||
{
|
||||
animations.push(AnimationInstruction::PriorityChange(
|
||||
entity_key,
|
||||
change,
|
||||
self.map.get(entity_key).and_then(|e| e.change_effect()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let Some(entity) = &self.map.get(entity_key) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let desired_location = entity.location + direction.into();
|
||||
let surface = map.get(desired_location);
|
||||
if surface == MapElement::Wall {
|
||||
let wall_resolution = resolve_wall_move(&entity.entity);
|
||||
match wall_resolution {
|
||||
WallResolution::Die => {
|
||||
hero_has_died |= self.kill_entity(entity_key, &mut animations);
|
||||
}
|
||||
WallResolution::StayPut => {
|
||||
animations.push(AnimationInstruction::FakeOutMove(
|
||||
entity_key,
|
||||
direction,
|
||||
entity.fake_out_wall_effect(),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// what is at that location
|
||||
let resolutions: Vec<_> = self
|
||||
.whats_at(desired_location)
|
||||
.filter(|(k, _)| *k != entity_key)
|
||||
.map(|(key, other_entity)| (key, resolve_move(entity, other_entity)))
|
||||
.collect();
|
||||
|
||||
let mut can_move = true;
|
||||
let mut explicit_stay_put = false;
|
||||
|
||||
for (other, resolution) in resolutions {
|
||||
match resolution {
|
||||
MoveAttemptResolution::KillDie => {
|
||||
hero_has_died |= self.kill_entity(other, &mut animations);
|
||||
hero_has_died |= self.kill_entity(entity_key, &mut animations);
|
||||
can_move = false;
|
||||
}
|
||||
MoveAttemptResolution::Kill => {
|
||||
hero_has_died |= self.kill_entity(other, &mut animations);
|
||||
can_move = false;
|
||||
}
|
||||
MoveAttemptResolution::Die => {
|
||||
hero_has_died |= self.kill_entity(entity_key, &mut animations);
|
||||
can_move = false;
|
||||
}
|
||||
MoveAttemptResolution::CoExist => {}
|
||||
MoveAttemptResolution::StayPut => {
|
||||
can_move = false;
|
||||
explicit_stay_put = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if can_move {
|
||||
if let Some(e) = self.map.get_mut(entity_key) {
|
||||
e.location = desired_location;
|
||||
}
|
||||
let Some(entity) = &self.map.get(entity_key) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
animations.push(AnimationInstruction::Move(
|
||||
entity_key,
|
||||
desired_location,
|
||||
entity.move_effect(),
|
||||
));
|
||||
|
||||
let overlap_resolutions: Vec<_> = self
|
||||
.whats_at(desired_location)
|
||||
.filter(|(k, _)| *k != entity_key)
|
||||
.map(|(key, other_entity)| {
|
||||
(key, resolve_overlap(entity, other_entity))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if overlap_resolutions
|
||||
.iter()
|
||||
.filter(|(_, r)| *r == OverlapResolution::Die)
|
||||
.count()
|
||||
!= 0
|
||||
{
|
||||
hero_has_died |= self.kill_entity(entity_key, &mut animations);
|
||||
} else {
|
||||
for (other, resolution) in overlap_resolutions {
|
||||
match resolution {
|
||||
OverlapResolution::Pickup => {
|
||||
animations.push(AnimationInstruction::Attach(
|
||||
entity_key,
|
||||
other,
|
||||
self.map
|
||||
.get(other)
|
||||
.and_then(|x| x.pickup_sound_effect()),
|
||||
));
|
||||
let other = self.map.remove(other).unwrap();
|
||||
|
||||
if let Some((location, dropped)) =
|
||||
self.map.get_mut(entity_key).and_then(|x| {
|
||||
x.pickup(other.entity).map(|y| (x.location, y))
|
||||
})
|
||||
{
|
||||
let new_key = self.map.insert(Entity {
|
||||
location,
|
||||
entity: dropped,
|
||||
});
|
||||
|
||||
animations.push(AnimationInstruction::Detatch(
|
||||
entity_key,
|
||||
new_key,
|
||||
self.map
|
||||
.get(new_key)
|
||||
.and_then(|x| x.drop_effect()),
|
||||
));
|
||||
}
|
||||
}
|
||||
OverlapResolution::CoExist => {}
|
||||
OverlapResolution::Win => {
|
||||
win_has_triggered = true;
|
||||
}
|
||||
OverlapResolution::ToggleSystem(system) => {
|
||||
for (k, e) in self.map.iter_mut() {
|
||||
if let Some(change) = e.switch(system) {
|
||||
animations.push(AnimationInstruction::Change(
|
||||
k,
|
||||
change,
|
||||
e.change_effect(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
OverlapResolution::Die => {
|
||||
// already handled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
animations.push(AnimationInstruction::FakeOutMove(
|
||||
entity_key,
|
||||
direction,
|
||||
if explicit_stay_put {
|
||||
self.map
|
||||
.get(entity_key)
|
||||
.and_then(|e| e.fake_out_wall_effect())
|
||||
} else {
|
||||
self.map.get(entity_key).and_then(|e| e.fake_out_effect())
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
if hero_has_died {
|
||||
Outcome::Loss
|
||||
} else if win_has_triggered {
|
||||
Outcome::Win
|
||||
} else {
|
||||
Outcome::Continue
|
||||
},
|
||||
animations,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum MoveAttemptResolution {
|
||||
Kill,
|
||||
Die,
|
||||
KillDie,
|
||||
CoExist,
|
||||
StayPut,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub struct SwitchSystem(usize);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
enum OverlapResolution {
|
||||
Pickup,
|
||||
CoExist,
|
||||
Win,
|
||||
ToggleSystem(SwitchSystem),
|
||||
Die,
|
||||
}
|
||||
|
||||
enum WallResolution {
|
||||
Die,
|
||||
StayPut,
|
||||
}
|
||||
|
||||
fn resolve_spikes(switable: &Switchable) -> OverlapResolution {
|
||||
if switable.active {
|
||||
OverlapResolution::Die
|
||||
} else {
|
||||
OverlapResolution::CoExist
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution {
|
||||
match (&me.entity, &other.entity) {
|
||||
(EntityType::Hero(_), EntityType::Stairs) => OverlapResolution::Win,
|
||||
(_, EntityType::Item(_)) => OverlapResolution::Pickup,
|
||||
(_, EntityType::Spikes(switch)) => resolve_spikes(switch),
|
||||
(_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system),
|
||||
(_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die,
|
||||
|
||||
_ => OverlapResolution::CoExist,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_wall_move(entity: &EntityType) -> WallResolution {
|
||||
WallResolution::StayPut
|
||||
}
|
||||
|
||||
fn holding_attack_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution {
|
||||
match holding {
|
||||
Some(&EntityType::Item(Item::Sword)) => MoveAttemptResolution::Kill,
|
||||
_ => MoveAttemptResolution::CoExist,
|
||||
}
|
||||
}
|
||||
|
||||
fn squid_holding_attack_resolve(me: &Squid, other: &Entity) -> MoveAttemptResolution {
|
||||
match (me.holding.as_deref(), &other.entity, other.holding()) {
|
||||
(
|
||||
Some(&EntityType::Item(Item::Sword)),
|
||||
EntityType::Enemy(Enemy::Squid(squid)),
|
||||
Some(&EntityType::Item(Item::Sword)),
|
||||
) => {
|
||||
if squid.direction == -me.direction {
|
||||
MoveAttemptResolution::KillDie
|
||||
} else {
|
||||
MoveAttemptResolution::Kill
|
||||
}
|
||||
}
|
||||
(Some(&EntityType::Item(Item::Sword)), EntityType::Enemy(_), None) => {
|
||||
MoveAttemptResolution::Kill
|
||||
}
|
||||
(_, EntityType::Enemy(Enemy::Squid(squid)), Some(&EntityType::Item(Item::Sword))) => {
|
||||
if squid.direction == -me.direction {
|
||||
MoveAttemptResolution::Die
|
||||
} else {
|
||||
MoveAttemptResolution::StayPut
|
||||
}
|
||||
}
|
||||
(_, EntityType::Enemy(_), _) => MoveAttemptResolution::StayPut,
|
||||
(_, EntityType::Hero(_), _) => MoveAttemptResolution::Kill,
|
||||
_ => MoveAttemptResolution::CoExist,
|
||||
}
|
||||
}
|
||||
|
||||
fn holding_door_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution {
|
||||
match holding {
|
||||
Some(&EntityType::Item(Item::Key)) => MoveAttemptResolution::Kill,
|
||||
_ => MoveAttemptResolution::StayPut,
|
||||
}
|
||||
}
|
||||
|
||||
fn switch_door_resolve(door: &Switchable) -> MoveAttemptResolution {
|
||||
if door.active {
|
||||
MoveAttemptResolution::CoExist
|
||||
} else {
|
||||
MoveAttemptResolution::StayPut
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_move(mover: &Entity, into: &Entity) -> MoveAttemptResolution {
|
||||
match (&mover.entity, &into.entity) {
|
||||
(EntityType::Hero(hero), EntityType::Hero(_) | EntityType::Enemy(_)) => {
|
||||
holding_attack_resolve(hero.holding.as_deref())
|
||||
}
|
||||
(EntityType::Hero(hero), EntityType::Door) => holding_door_resolve(hero.holding.as_deref()),
|
||||
(EntityType::Enemy(Enemy::Squid(squid)), EntityType::Hero(_) | EntityType::Enemy(_)) => {
|
||||
squid_holding_attack_resolve(squid, into)
|
||||
}
|
||||
(EntityType::Enemy(_), EntityType::Hero(_) | EntityType::Enemy(_)) => {
|
||||
MoveAttemptResolution::Kill
|
||||
}
|
||||
(_, EntityType::SwitchedDoor(door)) => switch_door_resolve(door),
|
||||
(EntityType::Enemy(Enemy::Squid(squid)), EntityType::Door) => {
|
||||
holding_door_resolve(squid.holding.as_deref())
|
||||
}
|
||||
(_, EntityType::Door) => MoveAttemptResolution::StayPut,
|
||||
(_, _) => MoveAttemptResolution::CoExist,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Hero {
|
||||
holding: Option<Box<EntityType>>,
|
||||
}
|
||||
|
||||
pub struct Entity {
|
||||
location: Vector2D<i32>,
|
||||
entity: EntityType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Switchable {
|
||||
system: SwitchSystem,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EntityType {
|
||||
Hero(Hero),
|
||||
Item(Item),
|
||||
Enemy(Enemy),
|
||||
Stairs,
|
||||
Door,
|
||||
SwitchedDoor(Switchable),
|
||||
Switch(Switchable),
|
||||
Spikes(Switchable),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Squid {
|
||||
direction: Direction,
|
||||
holding: Option<Box<EntityType>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Enemy {
|
||||
Slime,
|
||||
Squid(Squid),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Item {
|
||||
Sword,
|
||||
Key,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Neg for Direction {
|
||||
type Output = Direction;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
match self {
|
||||
Direction::Up => Direction::Down,
|
||||
Direction::Down => Direction::Up,
|
||||
Direction::Left => Direction::Right,
|
||||
Direction::Right => Direction::Left,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Direction> for Vector2D<i32> {
|
||||
fn from(val: Direction) -> Self {
|
||||
(&val).into()
|
||||
}
|
||||
}
|
||||
impl From<&Direction> for Vector2D<i32> {
|
||||
fn from(val: &Direction) -> Self {
|
||||
match val {
|
||||
Direction::Up => (0, -1),
|
||||
Direction::Down => (0, 1),
|
||||
Direction::Left => (-1, 0),
|
||||
Direction::Right => (1, 0),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum Action {
|
||||
Nothing,
|
||||
Direction(Direction),
|
||||
ChangeDirection(Direction),
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
fn desired_action(&self, walls: &Map, entities: &EntityMap, hero_action: Action) -> Action {
|
||||
match &self.entity {
|
||||
EntityType::Hero(_) => hero_action,
|
||||
EntityType::Enemy(Enemy::Squid(squid)) => {
|
||||
let desired_location = self.location + squid.direction.into();
|
||||
let wall = walls.get(desired_location);
|
||||
|
||||
if matches!(wall, MapElement::Wall) {
|
||||
Action::ChangeDirection(-squid.direction)
|
||||
} else {
|
||||
let can_move = entities
|
||||
.whats_at(desired_location)
|
||||
.map(|(_, other_entity)| resolve_move(self, other_entity))
|
||||
.filter(|resolution| matches!(resolution, MoveAttemptResolution::StayPut))
|
||||
.count()
|
||||
== 0;
|
||||
|
||||
if can_move {
|
||||
Action::Direction(squid.direction)
|
||||
} else {
|
||||
Action::ChangeDirection(-squid.direction)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Action::Nothing,
|
||||
}
|
||||
}
|
||||
|
||||
fn pickup(&mut self, item: EntityType) -> Option<EntityType> {
|
||||
let holding = match &mut self.entity {
|
||||
EntityType::Hero(hero) => &mut hero.holding,
|
||||
EntityType::Enemy(Enemy::Squid(squid)) => &mut squid.holding,
|
||||
_ => panic!("this entity can't pick up things"),
|
||||
};
|
||||
|
||||
let existing = core::mem::replace(holding, Some(Box::new(item)));
|
||||
existing.map(|x| *x)
|
||||
}
|
||||
|
||||
fn take_holding(&mut self) -> Option<EntityType> {
|
||||
match &mut self.entity {
|
||||
EntityType::Hero(hero) => hero.holding.take().map(|x| *x),
|
||||
EntityType::Enemy(Enemy::Squid(squid)) => squid.holding.take().map(|x| *x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn holding(&self) -> Option<&EntityType> {
|
||||
match &self.entity {
|
||||
EntityType::Hero(hero) => hero.holding.as_deref(),
|
||||
EntityType::Enemy(Enemy::Squid(squid)) => squid.holding.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn die_effect(&self) -> Option<SoundEffect> {
|
||||
match &self.entity {
|
||||
EntityType::Hero(_) => Some(SoundEffect::HeroDie),
|
||||
EntityType::Door => Some(SoundEffect::DoorOpen),
|
||||
EntityType::Enemy(Enemy::Slime) => Some(SoundEffect::SlimeDie),
|
||||
EntityType::Enemy(Enemy::Squid(_)) => Some(SoundEffect::SquidDie),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_effect(&self) -> Option<SoundEffect> {
|
||||
match &self.entity {
|
||||
EntityType::Item(Item::Key) => Some(SoundEffect::KeyDrop),
|
||||
EntityType::Item(Item::Sword) => Some(SoundEffect::SwordDrop),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn move_effect(&self) -> Option<SoundEffect> {
|
||||
None
|
||||
}
|
||||
|
||||
fn kill_sound_effect(&self) -> Option<SoundEffect> {
|
||||
None
|
||||
}
|
||||
|
||||
fn change_effect(&self) -> Option<SoundEffect> {
|
||||
match &self.entity {
|
||||
EntityType::Switch(_) => Some(SoundEffect::SwitchToggle),
|
||||
EntityType::SwitchedDoor(_) => Some(SoundEffect::SwitchedDoorToggle),
|
||||
EntityType::Spikes(_) => Some(SoundEffect::SpikesToggle),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn fake_out_wall_effect(&self) -> Option<SoundEffect> {
|
||||
match &self.entity {
|
||||
EntityType::Hero(_) => Some(SoundEffect::WallHit),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn pickup_sound_effect(&self) -> Option<SoundEffect> {
|
||||
match &self.entity {
|
||||
EntityType::Item(Item::Key) => Some(SoundEffect::KeyPickup),
|
||||
EntityType::Item(Item::Sword) => Some(SoundEffect::SwordPickup),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn fake_out_effect(&self) -> Option<SoundEffect> {
|
||||
None
|
||||
}
|
||||
|
||||
fn change_direction(&mut self) -> Option<level::Item> {
|
||||
match &mut self.entity {
|
||||
EntityType::Enemy(Enemy::Squid(squid)) => {
|
||||
squid.direction = -squid.direction;
|
||||
|
||||
if squid.direction == Direction::Up {
|
||||
Some(level::Item::SquidUp)
|
||||
} else {
|
||||
Some(level::Item::SquidDown)
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn switch(&mut self, system: SwitchSystem) -> Option<level::Item> {
|
||||
if let EntityType::SwitchedDoor(door) = &mut self.entity {
|
||||
if door.system == system {
|
||||
door.active = !door.active;
|
||||
return Some(if door.active {
|
||||
level::Item::SwitchedOpenDoor
|
||||
} else {
|
||||
level::Item::SwitchedClosedDoor
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let EntityType::Switch(switch) = &mut self.entity {
|
||||
if switch.system == system {
|
||||
switch.active = !switch.active;
|
||||
return Some(if switch.active {
|
||||
level::Item::SwitchPressed
|
||||
} else {
|
||||
level::Item::Switch
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let EntityType::Spikes(switch) = &mut self.entity {
|
||||
if switch.system == system {
|
||||
switch.active = !switch.active;
|
||||
return Some(if switch.active {
|
||||
level::Item::SpikesUp
|
||||
} else {
|
||||
level::Item::SpikesDown
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl From<level::Entity> for Entity {
|
||||
fn from(value: level::Entity) -> Self {
|
||||
Entity {
|
||||
location: value.1,
|
||||
entity: value.0.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<level::Item> for EntityType {
|
||||
fn from(value: level::Item) -> Self {
|
||||
match value {
|
||||
level::Item::Hero => EntityType::Hero(Hero { holding: None }),
|
||||
level::Item::Slime => EntityType::Enemy(Enemy::Slime),
|
||||
level::Item::Stairs => EntityType::Stairs,
|
||||
level::Item::Sword => EntityType::Item(Item::Sword),
|
||||
level::Item::Door => EntityType::Door,
|
||||
level::Item::Key => EntityType::Item(Item::Key),
|
||||
level::Item::SwitchedOpenDoor => EntityType::SwitchedDoor(Switchable {
|
||||
system: SwitchSystem(0),
|
||||
active: true,
|
||||
}),
|
||||
level::Item::SwitchedClosedDoor => EntityType::SwitchedDoor(Switchable {
|
||||
system: SwitchSystem(0),
|
||||
active: false,
|
||||
}),
|
||||
level::Item::Switch => EntityType::Switch(Switchable {
|
||||
system: SwitchSystem(0),
|
||||
active: false,
|
||||
}),
|
||||
level::Item::SwitchPressed => EntityType::Switch(Switchable {
|
||||
system: SwitchSystem(0),
|
||||
active: true,
|
||||
}),
|
||||
level::Item::SpikesUp => EntityType::Spikes(Switchable {
|
||||
system: SwitchSystem(0),
|
||||
active: true,
|
||||
}),
|
||||
level::Item::SpikesDown => EntityType::Spikes(Switchable {
|
||||
system: SwitchSystem(0),
|
||||
active: false,
|
||||
}),
|
||||
level::Item::SquidUp => EntityType::Enemy(Enemy::Squid(Squid {
|
||||
direction: Direction::Up,
|
||||
holding: None,
|
||||
})),
|
||||
level::Item::SquidDown => EntityType::Enemy(Enemy::Squid(Squid {
|
||||
direction: Direction::Down,
|
||||
holding: None,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
126
examples/the-dungeon-keepers-lament/src/level.rs
Normal file
126
examples/the-dungeon-keepers-lament/src/level.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
use agb::{display::object::Tag, fixnum::Vector2D};
|
||||
|
||||
use crate::{game::Direction, map::Map, resources};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum Item {
|
||||
Sword,
|
||||
Slime,
|
||||
Hero,
|
||||
Stairs,
|
||||
Door,
|
||||
Key,
|
||||
SwitchedOpenDoor,
|
||||
SwitchedClosedDoor,
|
||||
Switch,
|
||||
SwitchPressed,
|
||||
SpikesUp,
|
||||
SpikesDown,
|
||||
SquidUp,
|
||||
SquidDown,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn shadow_tag(&self) -> &'static Tag {
|
||||
match self {
|
||||
Item::Sword => resources::SWORD_SHADOW,
|
||||
Item::Slime => resources::SLIME_SHADOW,
|
||||
Item::Hero => resources::HERO,
|
||||
Item::Stairs => resources::STAIRS,
|
||||
Item::Door => resources::DOOR,
|
||||
Item::Key => resources::KEY_SHADOW,
|
||||
Item::SwitchedOpenDoor => resources::SWITCHED_DOOR_OPEN,
|
||||
Item::SwitchedClosedDoor => resources::SWITCHED_DOOR_CLOSED,
|
||||
Item::Switch => resources::BUTTON_OFF,
|
||||
Item::SwitchPressed => resources::BUTTON_ON,
|
||||
Item::SpikesUp => resources::SPIKES_ON,
|
||||
Item::SpikesDown => resources::SPIKES_OFF,
|
||||
Item::SquidUp => resources::SQUID_UP_SHADOW,
|
||||
Item::SquidDown => resources::SQUID_DOWN_SHADOW,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> &'static Tag {
|
||||
match self {
|
||||
Item::Sword => resources::SWORD,
|
||||
Item::Slime => resources::SLIME,
|
||||
Item::Hero => resources::HERO,
|
||||
Item::Stairs => resources::STAIRS,
|
||||
Item::Door => resources::DOOR,
|
||||
Item::Key => resources::KEY,
|
||||
Item::SwitchedOpenDoor => resources::SWITCHED_DOOR_OPEN,
|
||||
Item::SwitchedClosedDoor => resources::SWITCHED_DOOR_CLOSED,
|
||||
Item::Switch => resources::BUTTON_OFF,
|
||||
Item::SwitchPressed => resources::BUTTON_ON,
|
||||
Item::SpikesUp => resources::SPIKES_ON,
|
||||
Item::SpikesDown => resources::SPIKES_OFF,
|
||||
Item::SquidUp => resources::SQUID_UP,
|
||||
Item::SquidDown => resources::SQUID_DOWN,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_entity_offset(&self) -> Vector2D<i32> {
|
||||
const STANDARD: Vector2D<i32> = Vector2D::new(0, -3);
|
||||
const ZERO: Vector2D<i32> = Vector2D::new(0, 0);
|
||||
|
||||
match self {
|
||||
Item::Sword => STANDARD,
|
||||
Item::Slime => STANDARD,
|
||||
Item::Hero => STANDARD,
|
||||
Item::Stairs => ZERO,
|
||||
Item::Door => ZERO,
|
||||
Item::Key => STANDARD,
|
||||
Item::SwitchedOpenDoor => ZERO,
|
||||
Item::SwitchedClosedDoor => ZERO,
|
||||
Item::Switch => ZERO,
|
||||
Item::SwitchPressed => ZERO,
|
||||
Item::SpikesUp => ZERO,
|
||||
Item::SpikesDown => ZERO,
|
||||
Item::SquidUp => STANDARD,
|
||||
Item::SquidDown => STANDARD,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Entity(pub Item, pub Vector2D<i32>);
|
||||
|
||||
pub struct Level {
|
||||
pub map: Map<'static>,
|
||||
pub entities: &'static [Entity],
|
||||
pub directions: &'static [Direction],
|
||||
pub items: &'static [Item],
|
||||
pub name: &'static str,
|
||||
}
|
||||
|
||||
impl Level {
|
||||
const fn new(
|
||||
map: Map<'static>,
|
||||
entities: &'static [Entity],
|
||||
directions: &'static [Direction],
|
||||
items: &'static [Item],
|
||||
name: &'static str,
|
||||
) -> Self {
|
||||
Self {
|
||||
map,
|
||||
entities,
|
||||
directions,
|
||||
items,
|
||||
name,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn get_level(level_number: usize) -> &'static Level {
|
||||
&levels::LEVELS[level_number]
|
||||
}
|
||||
|
||||
pub const fn num_levels() -> usize {
|
||||
levels::LEVELS.len()
|
||||
}
|
||||
}
|
||||
|
||||
mod levels {
|
||||
use super::*;
|
||||
use agb::fixnum::Vector2D;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/levels.rs"));
|
||||
}
|
186
examples/the-dungeon-keepers-lament/src/lib.rs
Normal file
186
examples/the-dungeon-keepers-lament/src/lib.rs
Normal file
|
@ -0,0 +1,186 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![cfg_attr(test, feature(custom_test_frameworks))]
|
||||
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
|
||||
#![cfg_attr(test, test_runner(agb::test_runner::test_runner))]
|
||||
|
||||
use agb::{
|
||||
display::{
|
||||
object::{OamIterator, OamUnmanaged, SpriteLoader},
|
||||
tiled::{RegularBackgroundSize, TileFormat, TiledMap, VRamManager},
|
||||
Priority,
|
||||
},
|
||||
input::{Button, ButtonController},
|
||||
interrupt::VBlank,
|
||||
sound::mixer::Frequency,
|
||||
};
|
||||
use game::{Pausable, PauseSelection};
|
||||
|
||||
use sfx::Sfx;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod backgrounds;
|
||||
mod level;
|
||||
mod map;
|
||||
mod resources;
|
||||
mod sfx;
|
||||
|
||||
mod game;
|
||||
|
||||
mod save;
|
||||
|
||||
struct Agb<'gba> {
|
||||
vblank: VBlank,
|
||||
input: ButtonController,
|
||||
loader: SpriteLoader,
|
||||
sfx: Sfx<'gba>,
|
||||
vram: VRamManager,
|
||||
oam: OamUnmanaged<'gba>,
|
||||
}
|
||||
|
||||
impl<'gba> Agb<'gba> {
|
||||
fn frame<D, U, T, F>(&mut self, data: &mut D, update: U, render: F) -> T
|
||||
where
|
||||
U: FnOnce(
|
||||
&mut D,
|
||||
&ButtonController,
|
||||
&mut SpriteLoader,
|
||||
&mut Sfx<'gba>,
|
||||
&mut VRamManager,
|
||||
) -> T,
|
||||
F: FnOnce(&D, &mut OamIterator, &mut SpriteLoader),
|
||||
{
|
||||
self.vblank.wait_for_vblank();
|
||||
self.input.update();
|
||||
{
|
||||
render(data, &mut self.oam.iter(), &mut self.loader);
|
||||
}
|
||||
self.sfx.frame();
|
||||
|
||||
update(
|
||||
data,
|
||||
&self.input,
|
||||
&mut self.loader,
|
||||
&mut self.sfx,
|
||||
&mut self.vram,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn entry(mut gba: agb::Gba) -> ! {
|
||||
let vblank = VBlank::get();
|
||||
|
||||
let _ = save::init_save(&mut gba);
|
||||
|
||||
let (tiled, mut vram) = gba.display.video.tiled0();
|
||||
let mut ui_bg = tiled.background(
|
||||
Priority::P0,
|
||||
RegularBackgroundSize::Background32x32,
|
||||
TileFormat::FourBpp,
|
||||
);
|
||||
|
||||
let mut level_bg = tiled.background(
|
||||
Priority::P1,
|
||||
RegularBackgroundSize::Background32x32,
|
||||
TileFormat::FourBpp,
|
||||
);
|
||||
|
||||
let mut ending_bg = tiled.background(
|
||||
Priority::P0,
|
||||
RegularBackgroundSize::Background32x32,
|
||||
TileFormat::FourBpp,
|
||||
);
|
||||
backgrounds::load_ending_page(&mut ending_bg, &mut vram);
|
||||
ending_bg.commit(&mut vram);
|
||||
|
||||
backgrounds::load_palettes(&mut vram);
|
||||
backgrounds::load_ui(&mut ui_bg, &mut vram);
|
||||
|
||||
ui_bg.commit(&mut vram);
|
||||
ui_bg.show();
|
||||
|
||||
let (unmanaged, sprite_loader) = gba.display.object.get_unmanaged();
|
||||
|
||||
let mut input = agb::input::ButtonController::new();
|
||||
input.update();
|
||||
|
||||
if input.is_pressed(Button::START | Button::SELECT | Button::L | Button::R) {
|
||||
let _ = save::save_max_level(&mut gba.save, 0);
|
||||
}
|
||||
|
||||
let mut mixer = gba.mixer.mixer(Frequency::Hz18157);
|
||||
let sfx = Sfx::new(&mut mixer);
|
||||
|
||||
let mut g = Agb {
|
||||
vblank,
|
||||
input,
|
||||
loader: sprite_loader,
|
||||
sfx,
|
||||
vram,
|
||||
oam: unmanaged,
|
||||
};
|
||||
|
||||
let mut current_level = 0;
|
||||
let mut maximum_level = save::load_max_level() as usize;
|
||||
loop {
|
||||
if current_level >= level::Level::num_levels() {
|
||||
current_level = 0;
|
||||
ui_bg.hide();
|
||||
level_bg.hide();
|
||||
ending_bg.show();
|
||||
loop {
|
||||
if g.frame(
|
||||
&mut (),
|
||||
|_, input, _, _, _| input.is_just_pressed(Button::SELECT),
|
||||
|_, _, _| {},
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ui_bg.show();
|
||||
ending_bg.hide();
|
||||
} else {
|
||||
if current_level > maximum_level {
|
||||
maximum_level = current_level;
|
||||
let _ = save::save_max_level(&mut gba.save, maximum_level as u32);
|
||||
}
|
||||
let mut game = g.frame(
|
||||
&mut (),
|
||||
|_, _, loader, _, _| {
|
||||
Pausable::new(current_level, maximum_level, &mut level_bg, loader)
|
||||
},
|
||||
|_, _, _| {},
|
||||
);
|
||||
|
||||
loop {
|
||||
if let Some(option) = g.frame(
|
||||
&mut game,
|
||||
|game, input, loader, sfx, vram| game.update(input, sfx, loader, vram),
|
||||
|game, oam, loader| game.render(loader, oam),
|
||||
) {
|
||||
match option {
|
||||
game::UpdateResult::MenuSelection(PauseSelection::Restart) => break,
|
||||
game::UpdateResult::MenuSelection(PauseSelection::LevelSelect(level)) => {
|
||||
current_level = level;
|
||||
break;
|
||||
}
|
||||
game::UpdateResult::NextLevel => {
|
||||
current_level += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[agb::entry]
|
||||
fn agb_test_main(gba: agb::Gba) -> ! {
|
||||
loop {
|
||||
// full implementation provided by the #[entry]
|
||||
agb::syscall::halt();
|
||||
}
|
||||
}
|
10
examples/the-dungeon-keepers-lament/src/main.rs
Normal file
10
examples/the-dungeon-keepers-lament/src/main.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![cfg_attr(test, feature(custom_test_frameworks))]
|
||||
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
|
||||
#![cfg_attr(test, test_runner(agb::test_runner::test_runner))]
|
||||
|
||||
#[agb::entry]
|
||||
fn main(gba: agb::Gba) -> ! {
|
||||
the_dungeon_keepers_lament::entry(gba);
|
||||
}
|
83
examples/the-dungeon-keepers-lament/src/map.rs
Normal file
83
examples/the-dungeon-keepers-lament/src/map.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use core::ops::Index;
|
||||
|
||||
use agb::fixnum::Vector2D;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Map<'map> {
|
||||
width: usize,
|
||||
height: usize,
|
||||
data: &'map [u8],
|
||||
}
|
||||
|
||||
impl<'map> Map<'map> {
|
||||
pub const fn new(width: usize, height: usize, data: &'map [u8]) -> Self {
|
||||
assert!((width * height + 7) / 8 == data.len());
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn get(&self, index: Vector2D<i32>) -> MapElement {
|
||||
let (x, y) = (index.x, index.y);
|
||||
|
||||
if x > self.width as i32 || y > self.height as i32 {
|
||||
MapElement::Wall
|
||||
} else {
|
||||
let position = x as usize + y as usize * self.width;
|
||||
let index = position / 8;
|
||||
let bit = position % 8;
|
||||
if (self.data[index] & (1 << bit)) != 0 {
|
||||
MapElement::Wall
|
||||
} else {
|
||||
MapElement::Floor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<(i32, i32)> for Map<'_> {
|
||||
type Output = MapElement;
|
||||
|
||||
fn index(&self, index: (i32, i32)) -> &Self::Output {
|
||||
&self[Into::<Vector2D<i32>>::into(index)]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<Vector2D<i32>> for Map<'_> {
|
||||
type Output = MapElement;
|
||||
|
||||
fn index(&self, index: Vector2D<i32>) -> &Self::Output {
|
||||
const WALL: MapElement = MapElement::Wall;
|
||||
const FLOOR: MapElement = MapElement::Floor;
|
||||
|
||||
match self.get(index) {
|
||||
MapElement::Wall => &WALL,
|
||||
MapElement::Floor => &FLOOR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum MapElement {
|
||||
#[default]
|
||||
Wall,
|
||||
Floor,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test_case]
|
||||
fn check_default_is_correct(_: &mut agb::Gba) {
|
||||
let map = Map {
|
||||
width: 0,
|
||||
height: 0,
|
||||
data: &[],
|
||||
};
|
||||
|
||||
assert_eq!(map[(-1, -1)], MapElement::Wall);
|
||||
}
|
||||
}
|
55
examples/the-dungeon-keepers-lament/src/resources.rs
Normal file
55
examples/the-dungeon-keepers-lament/src/resources.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use agb::{
|
||||
display::{object::Graphics, Font},
|
||||
include_aseprite, include_font,
|
||||
};
|
||||
|
||||
const SPRITES: &Graphics = include_aseprite!(
|
||||
"gfx/sprites16x16.aseprite",
|
||||
"gfx/sprites8x8.aseprite",
|
||||
"gfx/countdown.aseprite"
|
||||
);
|
||||
|
||||
macro_rules! named_tag {
|
||||
(
|
||||
$sprites:ident, [
|
||||
$($name:tt),+ $(,)?
|
||||
] $(,)?
|
||||
) => {
|
||||
$(
|
||||
pub const $name: &agb::display::object::Tag = $sprites.tags().get(stringify!($name));
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
named_tag!(
|
||||
SPRITES,
|
||||
[
|
||||
SWORD,
|
||||
SWORD_SHADOW,
|
||||
SLIME,
|
||||
SLIME_SHADOW,
|
||||
STAIRS,
|
||||
HERO,
|
||||
HERO_CARRY,
|
||||
ARROW_LEFT,
|
||||
ARROW_RIGHT,
|
||||
ARROW_UP,
|
||||
ARROW_DOWN,
|
||||
CURSOR,
|
||||
KEY,
|
||||
KEY_SHADOW,
|
||||
DOOR,
|
||||
SWITCHED_DOOR_CLOSED,
|
||||
SWITCHED_DOOR_OPEN,
|
||||
SPIKES_ON,
|
||||
SPIKES_OFF,
|
||||
BUTTON_ON,
|
||||
BUTTON_OFF,
|
||||
SQUID_UP,
|
||||
SQUID_DOWN,
|
||||
SQUID_UP_SHADOW,
|
||||
SQUID_DOWN_SHADOW,
|
||||
]
|
||||
);
|
||||
|
||||
pub const FONT: Font = include_font!("fnt/yoster.ttf", 12);
|
46
examples/the-dungeon-keepers-lament/src/save.rs
Normal file
46
examples/the-dungeon-keepers-lament/src/save.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use agb::{
|
||||
save::{Error, SaveManager},
|
||||
sync::Static,
|
||||
Gba,
|
||||
};
|
||||
|
||||
static MAXIMUM_LEVEL: Static<u32> = Static::new(0);
|
||||
|
||||
pub fn init_save(gba: &mut Gba) -> Result<(), Error> {
|
||||
gba.save.init_sram();
|
||||
|
||||
let mut access = gba.save.access()?;
|
||||
|
||||
let mut buffer = [0; 1];
|
||||
access.read(0, &mut buffer)?;
|
||||
|
||||
if buffer[0] != 0 {
|
||||
access.prepare_write(0..1)?.write(0, &[0])?;
|
||||
core::mem::drop(access);
|
||||
save_max_level(&mut gba.save, 0)?;
|
||||
} else {
|
||||
let mut buffer = [0; 4];
|
||||
access.read(1, &mut buffer)?;
|
||||
let max_level = u32::from_le_bytes(buffer);
|
||||
|
||||
if max_level > 100 {
|
||||
MAXIMUM_LEVEL.write(0)
|
||||
} else {
|
||||
MAXIMUM_LEVEL.write(max_level)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_max_level() -> u32 {
|
||||
MAXIMUM_LEVEL.read()
|
||||
}
|
||||
|
||||
pub fn save_max_level(save: &mut SaveManager, level: u32) -> Result<(), Error> {
|
||||
save.access()?
|
||||
.prepare_write(1..5)?
|
||||
.write(1, &level.to_le_bytes())?;
|
||||
MAXIMUM_LEVEL.write(level);
|
||||
Ok(())
|
||||
}
|
104
examples/the-dungeon-keepers-lament/src/sfx.rs
Normal file
104
examples/the-dungeon-keepers-lament/src/sfx.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
use agb::{
|
||||
include_wav,
|
||||
sound::mixer::{Mixer, SoundChannel},
|
||||
};
|
||||
|
||||
const BGM: &[u8] = include_wav!("sfx/bgm.wav");
|
||||
const BAD_SELECTION: &[u8] = include_wav!("sfx/bad.wav");
|
||||
const SELECT: &[u8] = include_wav!("sfx/select.wav");
|
||||
const PLACE: &[u8] = include_wav!("sfx/place.wav");
|
||||
|
||||
const BANG: &[u8] = include_wav!("sfx/bang.wav");
|
||||
const SWORD_HIT: &[u8] = include_wav!("sfx/sword_hit.wav");
|
||||
const SLIME_DEATH: &[u8] = include_wav!("sfx/slime_death.wav");
|
||||
const SWORD_PICKUP: &[u8] = include_wav!("sfx/sword_pickup.wav");
|
||||
const WALL_HIT: &[u8] = include_wav!("sfx/wall_hit.wav");
|
||||
const DOOR_OPEN: &[u8] = include_wav!("sfx/door_open.wav");
|
||||
|
||||
const SWICTH_TOGGLES: &[&[u8]] = &[include_wav!("sfx/switch_toggle1.wav")];
|
||||
|
||||
pub struct Sfx<'a> {
|
||||
mixer: &'a mut Mixer<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Sfx<'a> {
|
||||
pub fn new(mixer: &'a mut Mixer<'a>) -> Self {
|
||||
let mut bgm_channel = SoundChannel::new_high_priority(BGM);
|
||||
bgm_channel.stereo().should_loop();
|
||||
|
||||
mixer.play_sound(bgm_channel);
|
||||
mixer.enable();
|
||||
|
||||
Self { mixer }
|
||||
}
|
||||
|
||||
pub fn frame(&mut self) {
|
||||
self.mixer.frame();
|
||||
}
|
||||
|
||||
pub fn bad_selection(&mut self) {
|
||||
self.mixer.play_sound(SoundChannel::new(BAD_SELECTION));
|
||||
}
|
||||
|
||||
pub fn select(&mut self) {
|
||||
self.mixer.play_sound(SoundChannel::new(SELECT));
|
||||
}
|
||||
|
||||
pub fn place(&mut self) {
|
||||
self.mixer.play_sound(SoundChannel::new(PLACE));
|
||||
}
|
||||
|
||||
pub fn play_sound_effect(&mut self, effect: Option<SoundEffect>) {
|
||||
if let Some(effect) = effect {
|
||||
match effect {
|
||||
SoundEffect::DoorFail | SoundEffect::WallHit => {
|
||||
self.mixer.play_sound(SoundChannel::new(WALL_HIT));
|
||||
}
|
||||
SoundEffect::SlimeDie => {
|
||||
self.mixer.play_sound(SoundChannel::new(SLIME_DEATH));
|
||||
}
|
||||
SoundEffect::HeroDie => {}
|
||||
SoundEffect::SquidDie => {}
|
||||
SoundEffect::SwordPickup => {
|
||||
self.mixer.play_sound(SoundChannel::new(SWORD_PICKUP));
|
||||
}
|
||||
SoundEffect::SwordKill => {
|
||||
self.mixer.play_sound(SoundChannel::new(SWORD_HIT));
|
||||
}
|
||||
SoundEffect::SwordFail => {
|
||||
self.mixer.play_sound(SoundChannel::new(BANG));
|
||||
}
|
||||
SoundEffect::KeyPickup => {}
|
||||
SoundEffect::DoorOpen => {
|
||||
self.mixer.play_sound(SoundChannel::new(DOOR_OPEN));
|
||||
}
|
||||
SoundEffect::SwitchToggle => {
|
||||
self.mixer.play_sound(SoundChannel::new(SWICTH_TOGGLES[0]));
|
||||
}
|
||||
SoundEffect::KeyDrop => {}
|
||||
SoundEffect::SwordDrop => {}
|
||||
SoundEffect::SwitchedDoorToggle => {}
|
||||
SoundEffect::SpikesToggle => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum SoundEffect {
|
||||
SlimeDie,
|
||||
HeroDie,
|
||||
SquidDie,
|
||||
SwordPickup,
|
||||
SwordKill,
|
||||
SwordFail,
|
||||
KeyPickup,
|
||||
DoorFail,
|
||||
DoorOpen,
|
||||
SwitchToggle,
|
||||
KeyDrop,
|
||||
SwordDrop,
|
||||
SwitchedDoorToggle,
|
||||
SpikesToggle,
|
||||
WallHit,
|
||||
}
|
Loading…
Reference in a new issue