Bladeren bron

Merge WASM

Herbert Wolverson 4 jaren geleden
bovenliggende
commit
359cdfe39d
79 gewijzigde bestanden met toevoegingen van 1056 en 453 verwijderingen
  1. 66 24
      Cargo.lock
  2. 7 0
      Cargo.toml
  3. 16 10
      book/src/chapter_1.md
  4. 2 0
      book/src/chapter_10.md
  5. 31 0
      book/src/chapter_11.md
  6. 2 0
      book/src/chapter_12.md
  7. 2 0
      book/src/chapter_13.md
  8. 26 14
      book/src/chapter_14.md
  9. 2 0
      book/src/chapter_16.md
  10. 2 0
      book/src/chapter_17.md
  11. 2 0
      book/src/chapter_18.md
  12. 30 16
      book/src/chapter_19.md
  13. 43 30
      book/src/chapter_2.md
  14. 2 0
      book/src/chapter_20.md
  15. 16 3
      book/src/chapter_21.md
  16. 14 7
      book/src/chapter_3.md
  17. 4 4
      book/src/chapter_4.md
  18. 10 7
      book/src/chapter_5.md
  19. 19 10
      book/src/chapter_6.md
  20. 25 21
      book/src/chapter_7.md
  21. 4 2
      book/src/chapter_8.md
  22. 10 5
      book/src/chapter_9.md
  23. 3 0
      chapter-01-hellorust/Cargo.toml
  24. 2 1
      chapter-01-hellorust/src/main.rs
  25. 5 1
      chapter-02-helloecs/Cargo.toml
  26. 14 8
      chapter-02-helloecs/src/main.rs
  27. 4 0
      chapter-03-walkmap/Cargo.toml
  28. 12 7
      chapter-03-walkmap/src/main.rs
  29. 4 0
      chapter-04-newmap/Cargo.toml
  30. 12 7
      chapter-04-newmap/src/main.rs
  31. 4 0
      chapter-05-fov/Cargo.toml
  32. 14 8
      chapter-05-fov/src/main.rs
  33. 4 0
      chapter-06-monsters/Cargo.toml
  34. 14 7
      chapter-06-monsters/src/main.rs
  35. 2 2
      chapter-06-monsters/src/monster_ai_system.rs
  36. 4 0
      chapter-07-damage/Cargo.toml
  37. 2 1
      chapter-07-damage/src/damage_system.rs
  38. 23 13
      chapter-07-damage/src/main.rs
  39. 3 2
      chapter-07-damage/src/melee_combat_system.rs
  40. 4 0
      chapter-08-ui/Cargo.toml
  41. 2 1
      chapter-08-ui/src/damage_system.rs
  42. 22 12
      chapter-08-ui/src/main.rs
  43. 4 0
      chapter-09-items/Cargo.toml
  44. 30 16
      chapter-09-items/src/main.rs
  45. 4 0
      chapter-10-ranged/Cargo.toml
  46. 31 17
      chapter-10-ranged/src/main.rs
  47. 4 0
      chapter-11-loadsave/Cargo.toml
  48. 32 18
      chapter-11-loadsave/src/main.rs
  49. 6 1
      chapter-11-loadsave/src/saveload_system.rs
  50. 4 0
      chapter-12-delvingdeeper/Cargo.toml
  51. 31 17
      chapter-12-delvingdeeper/src/main.rs
  52. 6 1
      chapter-12-delvingdeeper/src/saveload_system.rs
  53. 4 0
      chapter-13-difficulty/Cargo.toml
  54. 31 17
      chapter-13-difficulty/src/main.rs
  55. 6 1
      chapter-13-difficulty/src/saveload_system.rs
  56. 4 0
      chapter-14-gear/Cargo.toml
  57. 33 18
      chapter-14-gear/src/main.rs
  58. 6 1
      chapter-14-gear/src/saveload_system.rs
  59. 4 0
      chapter-16-nicewalls/Cargo.toml
  60. 33 18
      chapter-16-nicewalls/src/main.rs
  61. 6 1
      chapter-16-nicewalls/src/saveload_system.rs
  62. 4 0
      chapter-17-blood/Cargo.toml
  63. 33 18
      chapter-17-blood/src/main.rs
  64. 6 1
      chapter-17-blood/src/saveload_system.rs
  65. 4 0
      chapter-18-particles/Cargo.toml
  66. 35 19
      chapter-18-particles/src/main.rs
  67. 6 1
      chapter-18-particles/src/saveload_system.rs
  68. 4 0
      chapter-19-food/Cargo.toml
  69. 37 20
      chapter-19-food/src/main.rs
  70. 6 1
      chapter-19-food/src/saveload_system.rs
  71. 4 0
      chapter-20-magicmapping/Cargo.toml
  72. 37 20
      chapter-20-magicmapping/src/main.rs
  73. 6 1
      chapter-20-magicmapping/src/saveload_system.rs
  74. 4 0
      chapter-21-rexmenu/Cargo.toml
  75. 37 20
      chapter-21-rexmenu/src/main.rs
  76. 6 2
      chapter-21-rexmenu/src/rex_assets.rs
  77. 6 1
      chapter-21-rexmenu/src/saveload_system.rs
  78. 14 0
      index.html
  79. 39 0
      wasmbuild.bat

+ 66 - 24
Cargo.lock

@@ -154,198 +154,238 @@ dependencies = [
 name = "chapter-01-hellorust"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-02-helloecs"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-03-walkmap"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-04-newmap"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-05-fov"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-06-monsters"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-07-damage"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-08-ui"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-09-items"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-10-ranged"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-11-loadsave"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-12-delvingdeeper"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-13-difficulty"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-14-gear"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-16-nicewalls"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-17-blood"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-18-particles"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-19-food"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-20-magicmapping"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "chapter-21-rexmenu"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1322,8 +1362,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rltk"
-version = "0.3.0"
-source = "git+https://github.com/thebracket/rltk_rs#2e4b633159f612084caf9aa86d8196635ef9dd14"
+version = "0.3.1"
+source = "git+https://github.com/thebracket/rltk_rs#8fb1ab770f47baf9b71a74f1d11d7bdb5b42472c"
 dependencies = [
  "bresenham 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1348,9 +1388,11 @@ dependencies = [
 name = "rust_roguelike_tutorial"
 version = "0.1.0"
 dependencies = [
- "rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)",
+ "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2020,7 +2062,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b"
 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
 "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
-"checksum rltk 0.3.0 (git+https://github.com/thebracket/rltk_rs)" = "<none>"
+"checksum rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)" = "<none>"
 "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 "checksum rusttype 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5"

+ 7 - 0
Cargo.toml

@@ -11,6 +11,10 @@ rltk = { git = "https://github.com/thebracket/rltk_rs", features = [ "serializat
 specs = "0.15.0"
 specs-derive = "0.4.0"
 
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"
+
 [workspace]
 members = [ 
     "chapter-01-hellorust", 
@@ -34,3 +38,6 @@ members = [
     "chapter-20-magicmapping",
     "chapter-21-rexmenu"
     ]
+
+[profile.dev]
+opt-level = 1

File diff suppressed because it is too large
+ 16 - 10
book/src/chapter_1.md


+ 2 - 0
book/src/chapter_10.md

@@ -533,6 +533,8 @@ If this sees a `Confused` component, it decrements the timer. If the timer hits
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-10-ranged)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-10-ranged/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 31 - 0
book/src/chapter_11.md

@@ -657,12 +657,43 @@ gui::MainMenuSelection::LoadGame => {
 }
 ```
 
+## Web Assembly
+
+The example as-is will compile and run on the web assembly (`wasm32`) platform: but as soon as you try to save the game, it crashes. Unfortunately (well, fortunately if you like your computer not being attacked by every website you go to!), `wasm` is sandboxed - and doesn't have the ability to save files locally.
+
+Supporting saving via `LocalStorage` (a browser/JavaScript feature) is planned for a future version of RLTK. In the meantime, we'll add some wrappers to avoid the crash - and simply not actually save the game on `wasm32`.
+
+Rust offers *conditional compilation* (if you are familiar with C, it's a lot like the `#define` madness you find in big, cross-platform libraries). In `saveload_system.rs`, we'll modify `save_game` to only compile on non-web assembly platforms:
+
+```rust
+#[cfg(not(target_arch = "wasm32"))]
+pub fn save_game(ecs : &mut World) {
+```
+
+That `#` tag is scary looking, but it makes sense if you unwrap it. `#[cfg()]` means "only compile if the current configuration matches the contents of the parentheses. `not()` inverts the result of a check, so when we check that `target_arch = "wasm32")` (are we compiling for `wasm32`) the result is inverted. The end result of this is that the function only compiles if you *aren't* building for `wasm32`.
+
+That's all well and good, but there are calls to that function - so compilation on `wasm` will fail. We'll add a *stub* function to take its place:
+
+```rust
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+```
+
+The `#[cfg(target_arch = "wasm32")]` prefix means "only compile this for web assembly". We've kept the function signature the same, but added a `_` before `_ecs` - telling the compiler that we intend not to use that variable. Then we keep the function empty.
+
+The result? You can compile for `wasm32` and the `save_game` function simply doesn't *do* anything at all. The rest of the structure remains, so the game correctly returns to the main menu - but with no resume function.
+
+(Why does the check that the file exists work? Rust is smart enough to say "no filesystem, so the file can't exist". Thanks, Rust!)
+
 # Wrap-up
 
 This has been a long chapter, with quite heavy content. The great news is that we now have a framework for loading and saving the game whenever we want to. Adding components has gained some steps: we have to register them in `main`, tag them for `Serialize, Deserialize`, and remember to add them to our component type lists in `saveload_system.rs`. That could be easier - but it's a very solid foundation.
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-11-loadsave)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-11-loadsave/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 2 - 0
book/src/chapter_12.md

@@ -338,6 +338,8 @@ This chapter was a bit easier than the last couple! You can now descend through
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-12-delvingdeeper)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-12-delvingdeeper/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 2 - 0
book/src/chapter_13.md

@@ -261,6 +261,8 @@ You now have a dungeon that increases in difficulty as you descend! In the next
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-13-difficulty)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-13-difficulty/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 26 - 14
book/src/chapter_14.md

@@ -567,20 +567,30 @@ impl<'a> System<'a> for ItemRemoveSystem {
 Lastly, we add it to the systems in `main.rs`:
 
 ```rust
-let mut gs = State {
-    ecs: World::new(),
-    systems : DispatcherBuilder::new()
-        .with(MapIndexingSystem{}, "map_indexing_system", &[])
-        .with(VisibilitySystem{}, "visibility_system", &[])
-        .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-        .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-        .with(DamageSystem{}, "damage", &["melee_combat"])
-        .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-        .with(ItemUseSystem{}, "potions", &["melee_combat"])
-        .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-        .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-        .build(),
-};
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
+}
 ```
 
 Now if you `cargo run`, you can pick up a dagger or shield and equip it. Then you can press `R` to remove it.
@@ -808,6 +818,8 @@ That's it for the first section of the tutorial. It sticks relatively closely to
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-14-gear)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-14-gear/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 2 - 0
book/src/chapter_16.md

@@ -78,6 +78,8 @@ If you `cargo run` the project now, you get a nicer looking set of walls:
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-16-nicewalls)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-16-nicewalls/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 2 - 0
book/src/chapter_17.md

@@ -125,6 +125,8 @@ If you `cargo run` your project, the map starts to show signs of battle!
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-17-blood)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-17-blood/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 2 - 0
book/src/chapter_18.md

@@ -326,6 +326,8 @@ That's it for visual effects for now. We've given the game a much more visceral
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-18-particles)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-18-particles/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 30 - 16
book/src/chapter_19.md

@@ -138,22 +138,34 @@ It works by iterating all entities that have a `HungerClock`. If they are the pl
 Now we need to add it to the list of systems running in `main.rs`:
 
 ```rust
-let mut gs = State {
-    ecs: World::new(),
-    systems : DispatcherBuilder::new()
-        .with(MapIndexingSystem{}, "map_indexing_system", &[])
-        .with(VisibilitySystem{}, "visibility_system", &[])
-        .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-        .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-        .with(DamageSystem{}, "damage", &["melee_combat"])
-        .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-        .with(ItemUseSystem{}, "potions", &["melee_combat"])
-        .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-        .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-        .with(hunger_system::HungerSystem{}, "hunger", &["melee_combat", "potions"])
-        .with(particle_system::ParticleSpawnSystem{}, "spawn_particles", &["potions", "melee_combat"])
-        .build(),
-};
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+        let mut hunger = hunger_system::HungerSystem{};
+        hunger.run_now(&self.ecs);
+        let mut particles = particle_system::ParticleSpawnSystem{};
+        particles.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
+}
 ```
 
 If you `cargo run` now, and hit wait a *lot* - you'll starve to death.
@@ -322,6 +334,8 @@ We now have a working hunger clock system. You may want to tweak the durations t
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-19-food)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-19-food/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

File diff suppressed because it is too large
+ 43 - 30
book/src/chapter_2.md


+ 2 - 0
book/src/chapter_20.md

@@ -207,6 +207,8 @@ This was a relatively quick chapter, but we now have another staple of the rogue
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-20-magicmapping)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-20-magicmapping/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 16 - 3
book/src/chapter_21.md

@@ -26,22 +26,33 @@ We'll introduce a new file, `rex_assets.rs` to store our REX sprites. The file l
 
 ```rust
 use rltk::{rex::XpFile};
-use std::fs::File;
+
+rltk::embedded_resource!(SMALL_DUNGEON, "../../resources/SmallDungeon_80x50.xp");
 
 pub struct RexAssets {
     pub menu : XpFile
 }
 
 impl RexAssets {
+    #[allow(clippy::new_without_default)]
     pub fn new() -> RexAssets {
+        rltk::link_resource!(SMALL_DUNGEON, "../../resources/SmallDungeon_80x50.xp");
+
         RexAssets{
-            menu : XpFile::read(&mut File::open("../resources/SmallDungeon_80x50.xp").unwrap()).unwrap()
+            menu : XpFile::from_resource("../../resources/SmallDungeon_80x50.xp").unwrap()
         }
     }
 }
 ```
 
-Very simple - it defines a structure, and loads the dungeon graphic into it when `new` is called. We'll also insert it into Specs as a resource so we can access our sprites anywhere. In `main.rs`:
+Very simple - it defines a structure, and loads the dungeon graphic into it when `new` is called. We'll also insert it into Specs as a resource so we can access our sprites anywhere. There are some new concepts here:
+
+1. We're using `rltk::embedded_resource!` to include the file in our binary. This gets around having to ship the binary with your executable (and makes life easier in `wasm` land).
+2. `#[allow(clippy::new_without_default)]` tells the linter to stop telling me to write a default implementation, when we don't need one!
+3. `rltk::link_resource!` is the second-half the the embedded resource; the first stores it in memory, this one tells RLTK where to find it.
+4. `menu : XpFile::from_resource("../../resources/SmallDungeon_80x50.xp").unwrap()` loads the Rex paint file from memory.
+
+In `main.rs`:
 
 ```rust
 gs.ecs.insert(rex_assets::RexAssets::new());
@@ -112,6 +123,8 @@ If you `cargo run` now, it looks better:
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-21-rexmenu)**
 
+
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-21-rexmenu/)
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 14 - 7
book/src/chapter_3.md

@@ -187,6 +187,8 @@ use specs::prelude::*;
 #[macro_use]
 extern crate specs_derive;
 
+rltk::add_wasm_support!();
+
 #[derive(Component)]
 struct Position {
     x: i32,
@@ -209,8 +211,7 @@ enum TileType {
 }
 
 struct State {
-    ecs: World,
-    systems: Dispatcher<'static, 'static>
+    ecs: World
 }
 
 pub fn xy_idx(x: i32, y: i32) -> usize {
@@ -307,7 +308,7 @@ impl GameState for State {
         ctx.cls();
 
         player_input(self, ctx);
-        self.systems.dispatch(&self.ecs);
+        self.run_systems();
 
         let map = self.ecs.fetch::<Vec<TileType>>();
         draw_map(&map, ctx);
@@ -321,12 +322,16 @@ impl GameState for State {
     }
 }
 
+impl State {
+    fn run_systems(&mut self) {
+        self.ecs.maintain();
+    }
+}
+
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .build()
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();
@@ -351,6 +356,8 @@ fn main() {
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-03-walkmap)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-03-walkmap/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 4 - 4
book/src/chapter_4.md

@@ -229,11 +229,9 @@ Our `main.rs` file also required adjustment, to get accept the new format. We ch
 
 ```rust
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .build()
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();
@@ -296,6 +294,8 @@ You should now get something like this when you `cargo run` your project:
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-04-newmap)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-04-newmap/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 10 - 7
book/src/chapter_5.md

@@ -178,15 +178,16 @@ impl<'a> System<'a> for VisibilitySystem {
 }
 ```
 
-We adjust the systems registration in `main.rs`:
+Now we have to adjust `run_systems` in `main.rs` to actually call the system:
 
 ```rust
-let mut gs = State {
-    ecs: World::new(),
-    systems : DispatcherBuilder::new()
-        .with(VisibilitySystem{}, "visibility_system", &[])
-        .build()
-};
+impl State {
+    fn run_systems(&mut self) {
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
+}
 ```
 
 We also have to tell `main.rs` to use the new module:
@@ -547,6 +548,8 @@ If you `cargo run` your project, you will now have visible tiles as slightly cya
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-05-fov)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-05-fov/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 19 - 10
book/src/chapter_6.md

@@ -117,7 +117,7 @@ extern crate specs;
 use specs::prelude::*;
 use super::{Viewshed, Position, Map, Monster};
 extern crate rltk;
-use rltk::{field_of_view, Point};
+use rltk::{field_of_view, Point, console};
 
 pub struct MonsterAI {}
 
@@ -130,19 +130,26 @@ impl<'a> System<'a> for MonsterAI {
         let (viewshed, pos, monster) = data;
 
         for (viewshed,pos,_monster) in (&viewshed, &pos, &monster).join() {
-            println!("Monster considers their own existence");
+            console::log("Monster considers their own existence");
         }
     }
 }
 ```
 
-We'll also extend the system builder in `main.rs` to call it:
+Note that we're importing `console` from `rltk` - and printing with `console::log`. This is a helper provided by RLTK that detects if you are compiling to a regular program or a Web Assembly; if you are using a regular program, it calls `println!` and outputs to the console. If you are in `WASM`, it outputs to the *browser* console.
+
+We'll also extend the system runner in `main.rs` to call it:
 
 ```rust
-systems : DispatcherBuilder::new()
-    .with(VisibilitySystem{}, "visibility_system", &[])
-    .with(MonsterAI{}, "monster_ai", &["visibility_system"])
-    .build()
+impl State {
+    fn run_systems(&mut self) {
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
+}
 ```
 
 The `&["visibility_system"]` is new - it says "run this after visibility, since we depend upon its results. At this point, we don't actually care - but we will, so we'll put it in there now.
@@ -234,7 +241,7 @@ extern crate specs;
 use specs::prelude::*;
 use super::{Viewshed, Monster};
 extern crate rltk;
-use rltk::{Point};
+use rltk::{Point, console};
 
 pub struct MonsterAI {}
 
@@ -248,7 +255,7 @@ impl<'a> System<'a> for MonsterAI {
 
         for (viewshed,_monster) in (&viewshed, &monster).join() {
             if viewshed.visible_tiles.contains(&*player_pos) {
-                println!("Monster shouts insults");
+                console::log(format!("Monster shouts insults"));
             }
         }
     }
@@ -318,7 +325,7 @@ impl<'a> System<'a> for MonsterAI {
 
         for (viewshed,_monster,name) in (&viewshed, &monster, &name).join() {
             if viewshed.visible_tiles.contains(&*player_pos) {
-                println!("{} shouts insults", name.name);
+                console::log(&format!("{} shouts insults", name.name));
             }
         }
     }
@@ -333,6 +340,8 @@ And that's a wrap for chapter 6; we've added a variety of foul-mouthed monsters
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-06-monsters)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-06-monsters/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 25 - 21
book/src/chapter_7.md

@@ -52,7 +52,7 @@ extern crate specs;
 use specs::prelude::*;
 use super::{Viewshed, Monster, Name, Map, Position};
 extern crate rltk;
-use rltk::{Point};
+use rltk::{Point, console};
 
 pub struct MonsterAI {}
 
@@ -70,7 +70,7 @@ impl<'a> System<'a> for MonsterAI {
 
         for (mut viewshed,_monster,name,mut pos) in (&mut viewshed, &monster, &name, &mut position).join() {
             if viewshed.visible_tiles.contains(&*player_pos) {
-                println!("{} shouts insults", name.name);
+                console::log(&format!("{} shouts insults", name.name));
                 let path = rltk::a_star_search(
                     map.xy_idx(pos.x, pos.y) as i32, 
                     map.xy_idx(player_pos.x, player_pos.y) as i32, 
@@ -196,18 +196,20 @@ impl<'a> System<'a> for MapIndexingSystem {
 }
 ```
 
-This tells the map to setup blocking from the terrain, and then iterates all entities with a `BlocksTile` component, and applies them to the blocked list. We need to register it with the dispatcher; in `main.rs`:
+This tells the map to setup blocking from the terrain, and then iterates all entities with a `BlocksTile` component, and applies them to the blocked list. We need to register it with `run_systems`; in `main.rs`:
 
 ```rust
-let mut gs = State {
-    ecs: World::new(),
-    systems : DispatcherBuilder::new()
-        .with(MapIndexingSystem{}, "map_indexing_system", &[])
-        .with(VisibilitySystem{}, "visibility_system", &[])
-        .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-        .build(),
-    runstate : RunState::Running
-};
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
+}
 ```
 
 We didn't specify any dependencies, we're relying upon Specs to figure out if it can run concurrently with anything. We do however add it to the dependency list for `MonsterAI` - the AI relies on its results, so it has to be done.
@@ -218,7 +220,7 @@ If you `cargo run` now, monsters no longer end up on top of each other - but the
 let distance = rltk::DistanceAlg::Pythagoras.distance2d(Point::new(pos.x, pos.y), *player_pos);
 if distance < 1.5 {
     // Attack goes here
-    println!("{} shouts insults", name.name);
+    console::log(&format!("{} shouts insults", name.name));
     return;
 }
 ```
@@ -408,7 +410,7 @@ for (_player, pos, viewshed) in (&mut players, &mut positions, &mut viewsheds).j
             None => {}
             Some(t) => {
                 // Attack it
-                println!("From Hell's Heart, I stab thee!");
+                console::log(&format!("From Hell's Heart, I stab thee!"));
                 return; // So we don't move after attacking
             }
         }
@@ -478,9 +480,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
                     let damage = i32::max(0, stats.power - target_stats.defense);
 
                     if damage == 0 {
-                        println!("{} is unable to hurt {}", &name.name, &target_name.name);
+                        console::log(&format!("{} is unable to hurt {}", &name.name, &target_name.name));
                     } else {
-                        println!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage);
+                        console::log(&format!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage));
                         inflict_damage.insert(wants_melee.target, SufferDamage{ amount: damage }).expect("Unable to do damage");
                     }
                 }
@@ -635,7 +637,7 @@ pub fn delete_the_dead(ecs : &mut World) {
                 let player = players.get(entity);
                 match player {
                     None => dead.push(entity),
-                    Some(_) => println!("You are dead")
+                    Some(_) => console::log("You are dead")
                 }
             }
         }
@@ -686,18 +688,18 @@ fn tick(&mut self, ctx : &mut Rltk) {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
             RunState::AwaitingInput => {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
         }
@@ -728,7 +730,7 @@ In `player.rs` we simply replace all `Paused` with `AwaitingInput`, and `Running
 
 Lastly, we modify `monster_ai_system` to only run if the state is `MonsterTurn` (snippet):
 
-```
+```rust
 impl<'a> System<'a> for MonsterAI {
 #[allow(clippy::type_complexity)]
 type SystemData = ( WriteExpect<'a, Map>,
@@ -755,6 +757,8 @@ That was quite the chapter! We added in location indexing, damage, and killing t
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-07-damage)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-07-damage/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 4 - 2
book/src/chapter_8.md

@@ -174,7 +174,7 @@ pub fn delete_the_dead(ecs : &mut World) {
                         }
                         dead.push(entity)
                     }
-                    Some(_) => println!("You are dead")
+                    Some(_) => console::log("You are dead")
                 }
             }
         }
@@ -266,7 +266,7 @@ If you `cargo run` your project now, it looks like this:
 Since we're on look and feel, lets consider enabling an RLTK feature: post-processing to give scanlines and screen burn, for that truly retro feel. It's entirely up to you if you want to use this! In `main.rs`, the initial setup simply replaced the first `init` command with:
 
 ```rust
-let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
 context.with_post_scanlines(true);
 ```
 
@@ -280,6 +280,8 @@ Now that we have a GUI, it's starting to look pretty good!
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-08-ui)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-08-ui/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 10 - 5
book/src/chapter_9.md

@@ -326,7 +326,8 @@ impl<'a> System<'a> for ItemCollectionSystem {
 This iterates the requests to pick up an item, removes their position component, and adds an `InBackpack` component assigned to the collector. Don't forget to add it to the systems list in `main.rs`:
 
 ```rust
-.with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
+let mut pickup = ItemCollectionSystem{};
+pickup.run_now(&self.ecs);
 ```
 
 The next step is to add an input command to pick up an item. `g` is a popular key for this, so we'll go with that (we can always change it!). In `player.rs`, in the ever-growing `match` statement of inputs, we add:
@@ -551,7 +552,8 @@ impl<'a> System<'a> for PotionUseSystem {
 
 And register it in the list of systems to run:
 ```rust
-.with(PotionUseSystem{}, "potions", &["melee_combat"])
+let mut potions = PotionUseSystem{};
+potions.run_now(&self.ecs);
 ```
 
 Like other systems we've looked at, this iterates all of the `WantsToDrinkPotion` intent objects. It then heals up the drinker by the amount set in the `Potion` component, and deletes the potion. Since all of the placement information is attached to the potion itself, there's no need to chase around making sure it is removed from the appropriate backpack: the entity ceases to exist, and takes its components with it.
@@ -560,12 +562,12 @@ Testing this with `cargo run` gives a surprise: the potion isn't deleted after u
 
 ```rust
 RunState::PlayerTurn => {
-    self.systems.dispatch(&self.ecs);
+    self.run_systems();
     self.ecs.maintain();
     newrunstate = RunState::MonsterTurn;
 }
 RunState::MonsterTurn => {
-    self.systems.dispatch(&self.ecs);
+    self.run_systems();
     self.ecs.maintain();
     newrunstate = RunState::AwaitingInput;
 }
@@ -627,7 +629,8 @@ impl<'a> System<'a> for ItemDropSystem {
 
 Register it in the dispatch builder in `main.rs`:
 ```rust
-.with(ItemDropSystem{}, "drop_items", &["melee_combat"])
+let mut drop_items = ItemDropSystem{};
+drop_items.run_now(&self.ecs);
 ```
 
 We'll add a new `RunState` in `main.rs`:
@@ -751,6 +754,8 @@ This chapter has shown a fair amount of the power of using an ECS: picking up, u
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-09-items)**
 
+[Run this chapter's example with web assembly, in your browser (WebGL2 required)](http://bfnightly.bracketproductions.com/rustbook/wasm/chapter-09-items/)
+
 ---
 
 Copyright (C) 2019, Herbert Wolverson.

+ 3 - 0
chapter-01-hellorust/Cargo.toml

@@ -9,3 +9,6 @@ edition = "2018"
 [dependencies]
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 2 - 1
chapter-01-hellorust/src/main.rs

@@ -1,3 +1,4 @@
+rltk::add_wasm_support!();
 use rltk::{Rltk, GameState, Console};
 
 struct State {}
@@ -9,7 +10,7 @@ impl GameState for State {
 }
 
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let gs = State{ };
     rltk::main_loop(context, gs);
 }

+ 5 - 1
chapter-02-helloecs/Cargo.toml

@@ -8,5 +8,9 @@ edition = "2018"
 
 [dependencies]
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
-specs = "0.15.0"
+specs = { version = "0.15.0" }
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 14 - 8
chapter-02-helloecs/src/main.rs

@@ -3,6 +3,8 @@ use specs::prelude::*;
 #[macro_use]
 extern crate specs_derive;
 
+rltk::add_wasm_support!();
+
 #[derive(Component)]
 struct Position {
     x: i32,
@@ -23,8 +25,7 @@ struct LeftMover {}
 struct Player {}
 
 struct State {
-    ecs: World,
-    systems: Dispatcher<'static, 'static>
+    ecs: World
 }
 
 fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
@@ -61,7 +62,7 @@ impl GameState for State {
         ctx.cls();
 
         player_input(self, ctx);
-        self.systems.dispatch(&self.ecs);
+        self.run_systems();
 
         let positions = self.ecs.read_storage::<Position>();
         let renderables = self.ecs.read_storage::<Renderable>();
@@ -86,13 +87,18 @@ impl<'a> System<'a> for LeftWalker {
     }
 }
 
+impl State {
+    fn run_systems(&mut self) {
+        let mut lw = LeftWalker{};
+        lw.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
+}
+
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(LeftWalker{}, "left_walker", &[])
-            .build()
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 4 - 0
chapter-03-walkmap/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 12 - 7
chapter-03-walkmap/src/main.rs

@@ -3,6 +3,8 @@ use specs::prelude::*;
 #[macro_use]
 extern crate specs_derive;
 
+rltk::add_wasm_support!();
+
 #[derive(Component)]
 struct Position {
     x: i32,
@@ -25,8 +27,7 @@ enum TileType {
 }
 
 struct State {
-    ecs: World,
-    systems: Dispatcher<'static, 'static>
+    ecs: World
 }
 
 pub fn xy_idx(x: i32, y: i32) -> usize {
@@ -123,7 +124,7 @@ impl GameState for State {
         ctx.cls();
 
         player_input(self, ctx);
-        self.systems.dispatch(&self.ecs);
+        self.run_systems();
 
         let map = self.ecs.fetch::<Vec<TileType>>();
         draw_map(&map, ctx);
@@ -137,12 +138,16 @@ impl GameState for State {
     }
 }
 
+impl State {
+    fn run_systems(&mut self) {
+        self.ecs.maintain();
+    }
+}
+
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .build()
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 4 - 0
chapter-04-newmap/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 12 - 7
chapter-04-newmap/src/main.rs

@@ -11,9 +11,16 @@ use player::*;
 mod rect;
 pub use rect::Rect;
 
+rltk::add_wasm_support!();
+
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -21,7 +28,7 @@ impl GameState for State {
         ctx.cls();
 
         player_input(self, ctx);
-        self.systems.dispatch(&self.ecs);
+        self.run_systems();
 
         let map = self.ecs.fetch::<Vec<TileType>>();
         draw_map(&map, ctx);
@@ -36,11 +43,9 @@ impl GameState for State {
 }
 
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .build()
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 4 - 0
chapter-05-fov/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 14 - 8
chapter-05-fov/src/main.rs

@@ -15,9 +15,18 @@ pub use rect::Rect;
 mod visibility_system;
 use visibility_system::VisibilitySystem;
 
+rltk::add_wasm_support!();
+
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -25,7 +34,7 @@ impl GameState for State {
         ctx.cls();
 
         player_input(self, ctx);
-        self.systems.dispatch(&self.ecs);
+        self.run_systems();
 
         draw_map(&self.ecs, ctx);
 
@@ -39,12 +48,9 @@ impl GameState for State {
 }
 
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .build()
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 4 - 0
chapter-06-monsters/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 14 - 7
chapter-06-monsters/src/main.rs

@@ -17,21 +17,32 @@ use visibility_system::VisibilitySystem;
 mod monster_ai_system;
 use monster_ai_system::MonsterAI;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { Paused, Running }
 
 pub struct State {
     pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>,
     pub runstate : RunState
 }
 
+impl State {
+    fn run_systems(&mut self) {
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
+}
+
 impl GameState for State {
     fn tick(&mut self, ctx : &mut Rltk) {
         ctx.cls();
         
         if self.runstate == RunState::Running {
-            self.systems.dispatch(&self.ecs);
+            self.run_systems();
             self.runstate = RunState::Paused;
         } else {
             self.runstate = player_input(self, ctx);
@@ -51,13 +62,9 @@ impl GameState for State {
 }
 
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
         ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system"])
-            .build(),
         runstate : RunState::Running
     };
     gs.ecs.register::<Position>();

+ 2 - 2
chapter-06-monsters/src/monster_ai_system.rs

@@ -2,7 +2,7 @@ extern crate specs;
 use specs::prelude::*;
 use super::{Viewshed, Monster, Name};
 extern crate rltk;
-use rltk::{Point};
+use rltk::{Point, console};
 
 pub struct MonsterAI {}
 
@@ -17,7 +17,7 @@ impl<'a> System<'a> for MonsterAI {
 
         for (viewshed,_monster,name) in (&viewshed, &monster, &name).join() {
             if viewshed.visible_tiles.contains(&*player_pos) {
-                println!("{} shouts insults", name.name);
+                console::log(&format!("{} shouts insults", name.name));
             }
         }
     }

+ 4 - 0
chapter-07-damage/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 2 - 1
chapter-07-damage/src/damage_system.rs

@@ -1,6 +1,7 @@
 extern crate specs;
 use specs::prelude::*;
 use super::{CombatStats, SufferDamage, Player};
+use rltk::console;
 
 pub struct DamageSystem {}
 
@@ -31,7 +32,7 @@ pub fn delete_the_dead(ecs : &mut World) {
                 let player = players.get(entity);
                 match player {
                     None => dead.push(entity),
-                    Some(_) => println!("You are dead")
+                    Some(_) => console::log("You are dead")
                 }
             }
         }

+ 23 - 13
chapter-07-damage/src/main.rs

@@ -23,12 +23,29 @@ use melee_combat_system::MeleeCombatSystem;
 mod damage_system;
 use damage_system::DamageSystem;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, PreRun, PlayerTurn, MonsterTurn }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -42,18 +59,18 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
             RunState::AwaitingInput => {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
         }
@@ -78,16 +95,9 @@ impl GameState for State {
 }
 
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
         ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .build(),
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 3 - 2
chapter-07-damage/src/melee_combat_system.rs

@@ -1,6 +1,7 @@
 extern crate specs;
 use specs::prelude::*;
 use super::{CombatStats, WantsToMelee, Name, SufferDamage};
+use rltk::console;
 
 pub struct MeleeCombatSystem {}
 
@@ -24,9 +25,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
                     let damage = i32::max(0, stats.power - target_stats.defense);
 
                     if damage == 0 {
-                        println!("{} is unable to hurt {}", &name.name, &target_name.name);
+                        console::log(&format!("{} is unable to hurt {}", &name.name, &target_name.name));
                     } else {
-                        println!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage);
+                        console::log(&format!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage));
                         inflict_damage.insert(wants_melee.target, SufferDamage{ amount: damage }).expect("Unable to do damage");
                     }
                 }

+ 4 - 0
chapter-08-ui/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 2 - 1
chapter-08-ui/src/damage_system.rs

@@ -1,6 +1,7 @@
 extern crate specs;
 use specs::prelude::*;
 use super::{CombatStats, SufferDamage, Player, Name, gamelog::GameLog};
+use rltk::console;
 
 pub struct DamageSystem {}
 
@@ -39,7 +40,7 @@ pub fn delete_the_dead(ecs : &mut World) {
                         }
                         dead.push(entity)
                     }
-                    Some(_) => println!("You are dead")
+                    Some(_) => console::log("You are dead")
                 }
             }
         }

+ 22 - 12
chapter-08-ui/src/main.rs

@@ -25,12 +25,29 @@ use damage_system::DamageSystem;
 mod gui;
 mod gamelog;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, PreRun, PlayerTurn, MonsterTurn }
 
 pub struct State {
     pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -44,18 +61,18 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
             RunState::AwaitingInput => {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
         }
@@ -82,17 +99,10 @@ impl GameState for State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
         ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .build(),
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 4 - 0
chapter-09-items/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 30 - 16
chapter-09-items/src/main.rs

@@ -28,12 +28,36 @@ mod spawner;
 mod inventory_system;
 use inventory_system::{ ItemCollectionSystem, PotionUseSystem, ItemDropSystem };
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, PreRun, PlayerTurn, MonsterTurn, ShowInventory, ShowDropItem }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut potions = PotionUseSystem{};
+        potions.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -65,7 +89,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -73,12 +97,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -119,20 +143,10 @@ impl GameState for State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
         ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(PotionUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .build(),
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 4 - 0
chapter-10-ranged/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 31 - 17
chapter-10-ranged/src/main.rs

@@ -28,14 +28,38 @@ mod spawner;
 mod inventory_system;
 use inventory_system::{ ItemCollectionSystem, ItemUseSystem, ItemDropSystem };
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, PreRun, PlayerTurn, MonsterTurn, ShowInventory, ShowDropItem, 
     ShowTargeting { range : i32, item : Entity} }
 
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -67,7 +91,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -75,12 +99,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -139,20 +163,10 @@ impl GameState for State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 4 - 0
chapter-11-loadsave/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 32 - 18
chapter-11-loadsave/src/main.rs

@@ -31,6 +31,8 @@ mod inventory_system;
 use inventory_system::{ ItemCollectionSystem, ItemUseSystem, ItemDropSystem };
 pub mod saveload_system;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -44,8 +46,30 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -82,7 +106,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -90,12 +114,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -162,7 +186,7 @@ impl GameState for State {
             }
             RunState::SaveGame => {
                 saveload_system::save_game(&mut self.ecs);
-                newrunstate = RunState::MainMenu{ menu_selection : gui::MainMenuSelection::LoadGame };
+                newrunstate = RunState::MainMenu{ menu_selection : gui::MainMenuSelection::Quit };
             }
         }
 
@@ -175,20 +199,10 @@ impl GameState for State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-11-loadsave/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -55,7 +60,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-12-delvingdeeper/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 31 - 17
chapter-12-delvingdeeper/src/main.rs

@@ -31,6 +31,8 @@ mod inventory_system;
 use inventory_system::{ ItemCollectionSystem, ItemUseSystem, ItemDropSystem };
 pub mod saveload_system;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -45,8 +47,30 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -83,7 +107,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -91,12 +115,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -264,20 +288,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-12-delvingdeeper/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -55,7 +60,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-13-difficulty/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 31 - 17
chapter-13-difficulty/src/main.rs

@@ -32,6 +32,8 @@ use inventory_system::{ ItemCollectionSystem, ItemUseSystem, ItemDropSystem };
 pub mod saveload_system;
 pub mod random_table;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -46,8 +48,30 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -84,7 +108,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -92,12 +116,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -266,20 +290,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-13-difficulty/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -55,7 +60,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-14-gear/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 33 - 18
chapter-14-gear/src/main.rs

@@ -32,6 +32,8 @@ use inventory_system::{ ItemCollectionSystem, ItemUseSystem, ItemDropSystem, Ite
 pub mod saveload_system;
 pub mod random_table;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -48,8 +50,32 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -87,7 +113,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -95,12 +121,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -345,21 +371,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-14-gear/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -56,7 +61,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-16-nicewalls/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 33 - 18
chapter-16-nicewalls/src/main.rs

@@ -32,6 +32,8 @@ use inventory_system::{ ItemCollectionSystem, ItemUseSystem, ItemDropSystem, Ite
 pub mod saveload_system;
 pub mod random_table;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -48,8 +50,32 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -87,7 +113,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -95,12 +121,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -345,21 +371,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-16-nicewalls/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -56,7 +61,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-17-blood/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 33 - 18
chapter-17-blood/src/main.rs

@@ -32,6 +32,8 @@ use inventory_system::{ ItemCollectionSystem, ItemUseSystem, ItemDropSystem, Ite
 pub mod saveload_system;
 pub mod random_table;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -48,8 +50,32 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -87,7 +113,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -95,12 +121,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -345,21 +371,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-17-blood/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -56,7 +61,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-18-particles/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 35 - 19
chapter-18-particles/src/main.rs

@@ -33,6 +33,8 @@ pub mod saveload_system;
 pub mod random_table;
 pub mod particle_system;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -49,8 +51,34 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+        let mut particles = particle_system::ParticleSpawnSystem{};
+        particles.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -85,7 +113,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -93,12 +121,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -343,22 +371,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-            .with(particle_system::ParticleSpawnSystem{}, "spawn_particles", &["potions", "melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-18-particles/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -56,7 +61,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-19-food/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 37 - 20
chapter-19-food/src/main.rs

@@ -34,6 +34,8 @@ pub mod random_table;
 pub mod particle_system;
 pub mod hunger_system;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -50,8 +52,36 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+        let mut hunger = hunger_system::HungerSystem{};
+        hunger.run_now(&self.ecs);
+        let mut particles = particle_system::ParticleSpawnSystem{};
+        particles.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -86,7 +116,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -94,12 +124,12 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -344,23 +374,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-            .with(hunger_system::HungerSystem{}, "hunger", &["melee_combat", "potions"])
-            .with(particle_system::ParticleSpawnSystem{}, "spawn_particles", &["potions", "melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-19-food/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -56,7 +61,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-20-magicmapping/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 37 - 20
chapter-20-magicmapping/src/main.rs

@@ -34,6 +34,8 @@ pub mod random_table;
 pub mod particle_system;
 pub mod hunger_system;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -51,8 +53,36 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+        let mut hunger = hunger_system::HungerSystem{};
+        hunger.run_now(&self.ecs);
+        let mut particles = particle_system::ParticleSpawnSystem{};
+        particles.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -87,7 +117,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -95,7 +125,7 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 match *self.ecs.fetch::<RunState>() {
                     RunState::MagicMapReveal{ .. } => newrunstate = RunState::MagicMapReveal{ row: 0 },
@@ -103,7 +133,7 @@ impl GameState for State {
                 }                
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -360,23 +390,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-            .with(hunger_system::HungerSystem{}, "hunger", &["melee_combat", "potions"])
-            .with(particle_system::ParticleSpawnSystem{}, "spawn_particles", &["potions", "melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 1
chapter-20-magicmapping/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -56,7 +61,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 4 - 0
chapter-21-rexmenu/Cargo.toml

@@ -12,3 +12,7 @@ specs = { version = "0.15.0", features = ["serde"] }
 specs-derive = "0.4.0"
 serde= { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 37 - 20
chapter-21-rexmenu/src/main.rs

@@ -35,6 +35,8 @@ pub mod particle_system;
 pub mod hunger_system;
 pub mod rex_assets;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, 
     PreRun, 
@@ -52,8 +54,36 @@ pub enum RunState { AwaitingInput,
 }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        let mut pickup = ItemCollectionSystem{};
+        pickup.run_now(&self.ecs);
+        let mut itemuse = ItemUseSystem{};
+        itemuse.run_now(&self.ecs);
+        let mut drop_items = ItemDropSystem{};
+        drop_items.run_now(&self.ecs);
+        let mut item_remove = ItemRemoveSystem{};
+        item_remove.run_now(&self.ecs);
+        let mut hunger = hunger_system::HungerSystem{};
+        hunger.run_now(&self.ecs);
+        let mut particles = particle_system::ParticleSpawnSystem{};
+        particles.run_now(&self.ecs);
+
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -88,7 +118,7 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -96,7 +126,7 @@ impl GameState for State {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 match *self.ecs.fetch::<RunState>() {
                     RunState::MagicMapReveal{ .. } => newrunstate = RunState::MagicMapReveal{ row: 0 },
@@ -104,7 +134,7 @@ impl GameState for State {
                 }                
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 self.ecs.maintain();
                 newrunstate = RunState::AwaitingInput;
             }
@@ -361,23 +391,10 @@ impl State {
 }
 
 fn main() {
-    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     context.with_post_scanlines(true);
     let mut gs = State {
-        ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .with(ItemCollectionSystem{}, "pickup", &["melee_combat"])
-            .with(ItemUseSystem{}, "potions", &["melee_combat"])
-            .with(ItemDropSystem{}, "drop_items", &["melee_combat"])
-            .with(ItemRemoveSystem{}, "remove_items", &["melee_combat"])
-            .with(hunger_system::HungerSystem{}, "hunger", &["melee_combat", "potions"])
-            .with(particle_system::ParticleSpawnSystem{}, "spawn_particles", &["potions", "melee_combat"])
-            .build(),
+        ecs: World::new()
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 6 - 2
chapter-21-rexmenu/src/rex_assets.rs

@@ -1,14 +1,18 @@
 use rltk::{rex::XpFile};
-use std::fs::File;
+
+rltk::embedded_resource!(SMALL_DUNGEON, "../../resources/SmallDungeon_80x50.xp");
 
 pub struct RexAssets {
     pub menu : XpFile
 }
 
 impl RexAssets {
+    #[allow(clippy::new_without_default)]
     pub fn new() -> RexAssets {
+        rltk::link_resource!(SMALL_DUNGEON, "../../resources/SmallDungeon_80x50.xp");
+
         RexAssets{
-            menu : XpFile::read(&mut File::open("../resources/SmallDungeon_80x50.xp").unwrap()).unwrap()
+            menu : XpFile::from_resource("../../resources/SmallDungeon_80x50.xp").unwrap()
         }
     }
 }

+ 6 - 1
chapter-21-rexmenu/src/saveload_system.rs

@@ -20,6 +20,11 @@ macro_rules! serialize_individually {
     };
 }
 
+#[cfg(target_arch = "wasm32")]
+pub fn save_game(_ecs : &mut World) {
+}
+
+#[cfg(not(target_arch = "wasm32"))]
 pub fn save_game(ecs : &mut World) {
     // Create helper
     let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
@@ -56,7 +61,7 @@ macro_rules! deserialize_individually {
         $(
         DeserializeComponents::<NoError, _>::deserialize(
             &mut ( &mut $ecs.write_storage::<$type>(), ),
-            &mut $data.0, // entities
+            &$data.0, // entities
             &mut $data.1, // marker
             &mut $data.2, // allocater
             &mut $de,

+ 14 - 0
index.html

@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
+  </head>
+  <body>
+    <canvas id="canvas" width="640" height="480"></canvas>
+    <script src="./myblob.js"></script>
+    <script>
+      window.addEventListener("load", async () => {
+        await wasm_bindgen("./myblob_bg.wasm");
+      });
+    </script>
+  </body>
+</html>

+ 39 - 0
wasmbuild.bat

@@ -0,0 +1,39 @@
+@ECHO OFF
+
+CALL :Stage chapter-01-hellorust
+CALL :Stage chapter-02-helloecs
+CALL :Stage chapter-03-walkmap
+CALL :Stage chapter-04-newmap
+CALL :Stage chapter-05-fov
+CALL :Stage chapter-06-monsters
+CALL :Stage chapter-07-damage
+CALL :Stage chapter-08-ui
+CALL :Stage chapter-09-items
+CALL :Stage chapter-10-ranged
+CALL :Stage chapter-11-loadsave
+CALL :Stage chapter-12-delvingdeeper
+CALL :Stage chapter-13-difficulty
+CALL :Stage chapter-14-gear
+CALL :Stage chapter-16-nicewalls
+CALL :Stage chapter-17-blood
+CALL :Stage chapter-18-particles
+CALL :Stage chapter-19-food
+CALL :Stage chapter-20-magicmapping
+CALL :Stage chapter-21-rexmenu
+
+REM Publish or perish
+cd book\book\wasm
+pscp -r * herbert@172.16.10.193:/var/www/bfnightly/rustbook/wasm
+cd ..\..\..
+
+EXIT /B 0
+
+REM Usage: Stage Chapter
+:Stage
+cd %~1
+cargo build --release --target wasm32-unknown-unknown
+wasm-bindgen ..\target\wasm32-unknown-unknown\release\%~1.wasm --out-dir ../book/book/wasm/%~1 --no-modules --no-typescript
+cd ..
+move .\book\book\wasm\%~1\%~1.js .\book\book\wasm\%~1\myblob.js
+move .\book\book\wasm\%~1\%~1_bg.wasm ./book/book/wasm/%~1/myblob_bg.wasm
+copy index.html .\book\book\wasm\%~1