diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Idle0.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Idle0.png
new file mode 100644
index 0000000..367733f
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Idle0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run0.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run0.png
new file mode 100644
index 0000000..f1df19a
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run1.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run1.png
new file mode 100644
index 0000000..1ad16a3
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run1.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run2.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run2.png
new file mode 100644
index 0000000..2a0c1c3
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run2.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run3.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run3.png
new file mode 100644
index 0000000..561d9e8
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run3.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run4.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run4.png
new file mode 100644
index 0000000..9af1511
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run4.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run5.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run5.png
new file mode 100644
index 0000000..7808a21
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run5.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run6.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run6.png
new file mode 100644
index 0000000..e484a9f
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run6.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run7.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run7.png
new file mode 100644
index 0000000..974bd9a
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run7.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run8.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run8.png
new file mode 100644
index 0000000..e0d1360
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run8.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run9.png b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run9.png
new file mode 100644
index 0000000..9ab32f6
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male1/Male_1_Run9.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Idle0.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Idle0.png
new file mode 100644
index 0000000..955eb9e
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Idle0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run0.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run0.png
new file mode 100644
index 0000000..8704ba7
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run1.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run1.png
new file mode 100644
index 0000000..dfed4f0
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run1.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run2.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run2.png
new file mode 100644
index 0000000..db9a024
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run2.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run3.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run3.png
new file mode 100644
index 0000000..dc40232
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run3.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run4.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run4.png
new file mode 100644
index 0000000..681b4c1
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run4.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run5.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run5.png
new file mode 100644
index 0000000..2639c69
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run5.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run6.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run6.png
new file mode 100644
index 0000000..030a630
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run6.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run7.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run7.png
new file mode 100644
index 0000000..e7a47fb
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run7.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run8.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run8.png
new file mode 100644
index 0000000..fa7a55f
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run8.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run9.png b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run9.png
new file mode 100644
index 0000000..61ab8f2
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male2/Male_2_Run9.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Idle0.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Idle0.png
new file mode 100644
index 0000000..a089ebc
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Idle0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run0.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run0.png
new file mode 100644
index 0000000..2352da1
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run1.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run1.png
new file mode 100644
index 0000000..ce71eb5
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run1.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run2.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run2.png
new file mode 100644
index 0000000..75727e5
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run2.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run3.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run3.png
new file mode 100644
index 0000000..6572f25
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run3.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run4.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run4.png
new file mode 100644
index 0000000..30a3331
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run4.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run5.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run5.png
new file mode 100644
index 0000000..add7261
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run5.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run6.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run6.png
new file mode 100644
index 0000000..1cda4c6
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run6.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run7.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run7.png
new file mode 100644
index 0000000..0e3e5c6
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run7.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run8.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run8.png
new file mode 100644
index 0000000..458a8c5
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run8.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run9.png b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run9.png
new file mode 100644
index 0000000..fa6c903
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male3/Male_3_Run9.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Idle0.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Idle0.png
new file mode 100644
index 0000000..e25a05c
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Idle0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run0.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run0.png
new file mode 100644
index 0000000..6aca4a1
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run1.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run1.png
new file mode 100644
index 0000000..77af251
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run1.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run2.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run2.png
new file mode 100644
index 0000000..4c0793e
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run2.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run3.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run3.png
new file mode 100644
index 0000000..47731a4
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run3.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run4.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run4.png
new file mode 100644
index 0000000..71db17b
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run4.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run5.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run5.png
new file mode 100644
index 0000000..9394ae4
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run5.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run6.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run6.png
new file mode 100644
index 0000000..35b6023
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run6.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run7.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run7.png
new file mode 100644
index 0000000..51661e5
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run7.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run8.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run8.png
new file mode 100644
index 0000000..b3ace8b
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run8.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run9.png b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run9.png
new file mode 100644
index 0000000..7e73cbb
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male4/Male_4_Run9.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Idle0.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Idle0.png
new file mode 100644
index 0000000..b0d934f
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Idle0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run0.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run0.png
new file mode 100644
index 0000000..00992e2
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run1.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run1.png
new file mode 100644
index 0000000..387a1e9
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run1.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run2.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run2.png
new file mode 100644
index 0000000..7ca2c1e
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run2.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run3.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run3.png
new file mode 100644
index 0000000..e5edaea
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run3.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run4.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run4.png
new file mode 100644
index 0000000..b7db454
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run4.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run5.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run5.png
new file mode 100644
index 0000000..b06a8c1
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run5.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run6.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run6.png
new file mode 100644
index 0000000..c95a889
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run6.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run7.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run7.png
new file mode 100644
index 0000000..b90eaf6
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run7.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run8.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run8.png
new file mode 100644
index 0000000..fc15715
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run8.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run9.png b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run9.png
new file mode 100644
index 0000000..9c9130d
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male5/Male_5_Run9.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Idle0.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Idle0.png
new file mode 100644
index 0000000..ea00932
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Idle0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run0.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run0.png
new file mode 100644
index 0000000..1b35429
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run1.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run1.png
new file mode 100644
index 0000000..5ca61d2
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run1.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run2.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run2.png
new file mode 100644
index 0000000..bae055d
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run2.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run3.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run3.png
new file mode 100644
index 0000000..42ef2d2
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run3.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run4.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run4.png
new file mode 100644
index 0000000..ccc01d0
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run4.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run5.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run5.png
new file mode 100644
index 0000000..5eb0044
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run5.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run6.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run6.png
new file mode 100644
index 0000000..28c67aa
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run6.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run7.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run7.png
new file mode 100644
index 0000000..c3b786c
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run7.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run8.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run8.png
new file mode 100644
index 0000000..87c0eb1
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run8.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run9.png b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run9.png
new file mode 100644
index 0000000..1ee63f2
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male6/Male_6_Run9.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Idle0.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Idle0.png
new file mode 100644
index 0000000..9342287
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Idle0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run0.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run0.png
new file mode 100644
index 0000000..aa1e7ee
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run0.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run1.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run1.png
new file mode 100644
index 0000000..833597d
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run1.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run2.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run2.png
new file mode 100644
index 0000000..cc730d8
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run2.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run3.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run3.png
new file mode 100644
index 0000000..c2d3e67
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run3.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run4.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run4.png
new file mode 100644
index 0000000..65209bb
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run4.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run5.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run5.png
new file mode 100644
index 0000000..19a043e
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run5.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run6.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run6.png
new file mode 100644
index 0000000..ac186b9
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run6.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run7.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run7.png
new file mode 100644
index 0000000..2185a5e
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run7.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run8.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run8.png
new file mode 100644
index 0000000..a0813ae
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run8.png differ
diff --git a/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run9.png b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run9.png
new file mode 100644
index 0000000..4d73d90
Binary files /dev/null and b/html/assets/kenney/iso-dungeon/characters/male7/Male_7_Run9.png differ
diff --git a/html/js/render/assetPacks.js b/html/js/render/assetPacks.js
index ae0a94e..a1a2118 100644
--- a/html/js/render/assetPacks.js
+++ b/html/js/render/assetPacks.js
@@ -189,32 +189,39 @@
return out;
};
+ function isoMale(n) {
+ var base = 'assets/kenney/iso-dungeon/characters/male' + n + '/Male_' + n + '_';
+ var run = [];
+ for (var i = 0; i < 10; i++) run.push(base + 'Run' + i + '.png');
+ return {
+ idle: base + 'Idle0.png',
+ run: run,
+ imageW: 48,
+ imageH: 92
+ };
+ }
+
RK.isoAssets = {
pack: 'iso-dungeon',
tile: { w: 84, h: 42, imageW: 92, imageH: 184 },
tiles: {
floor: 'assets/kenney/iso-dungeon/tiles/planks_S.png',
- wall: 'assets/kenney/iso-dungeon/tiles/stoneWall_S.png',
+ wall: 'assets/kenney/iso-dungeon/tiles/stoneWallHalf_S.png',
bar: 'assets/kenney/iso-dungeon/tiles/barrelsStacked_S.png',
table: 'assets/kenney/iso-dungeon/tiles/chestClosed_S.png',
fallback: 'assets/kenney/iso-dungeon/tiles/planks_S.png'
},
- character: {
- idle: 'assets/kenney/iso-dungeon/characters/male0/Male_0_Idle0.png',
- run: [
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run0.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run1.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run2.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run3.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run4.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run5.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run6.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run7.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run8.png',
- 'assets/kenney/iso-dungeon/characters/male0/Male_0_Run9.png'
- ],
- imageW: 74,
- imageH: 148
+ character: isoMale(0),
+ characters: {
+ fallback: isoMale(0),
+ 'char-villager': isoMale(0),
+ 'char-elder': isoMale(1),
+ 'char-barbarian': isoMale(2),
+ 'char-monk': isoMale(3),
+ 'char-ranger': isoMale(4),
+ 'char-bard': isoMale(5),
+ 'char-rogue': isoMale(6),
+ 'char-merchant': isoMale(7)
}
};
diff --git a/html/js/render/charCustomize.js b/html/js/render/charCustomize.js
index 923e583..e282bb3 100644
--- a/html/js/render/charCustomize.js
+++ b/html/js/render/charCustomize.js
@@ -7,6 +7,8 @@
var DEFAULT_EQUIPMENT = { body: 'none', head: 'none', shield: 'none', weapon: 'none' };
var DEFAULT_COLORS = { base: 'none', skin: 'natural', hair: 'copper', body: 'none', head: 'none', shield: 'none', weapon: 'none' };
+ var thumbImages = {};
+ var thumbBounds = {};
function cloneEquipment(eq) {
eq = eq || {};
@@ -110,8 +112,169 @@
} catch (_) { return null; }
};
- function drawBaseThumb(ctx, a, draft, onReady) {
+ function projectionForMode(mode) {
+ if (mode === 'iso' || mode === '3d' || mode === 'ascii') return mode;
+ return 'topdown';
+ }
+
+ function hasIsoCharacter(a) {
+ return !!(a && a.kind === 'char' && RK.isoAssets && RK.isoAssets.characters && RK.isoAssets.characters[a.id]);
+ }
+
+ function appearanceVisibleInProjection(a, projection) {
+ if (!a) return false;
+ if (a.kind === 'color') return true;
+ if (projection === 'topdown') return a.kind === 'char' || a.kind === 'skin';
+ if (projection === 'iso') return hasIsoCharacter(a);
+ if (projection === '3d') return a.kind === 'model3d';
+ return false;
+ }
+
+ function loadThumbImage(url, onReady) {
+ if (!url) return null;
+ if (thumbImages[url]) return thumbImages[url];
+ var rec = thumbImages[url] = { ready: false, error: false, img: new Image() };
+ rec.img.onload = function () { rec.ready = true; if (onReady) onReady(); };
+ rec.img.onerror = function () { rec.error = true; };
+ rec.img.src = url;
+ return rec;
+ }
+
+ function tintColorForThumb(a, draft) {
+ var source = {};
+ var d = draft || {};
+ for (var dk in d) source[dk] = d[dk];
+ source.avatar = a.id;
+ if (a.kind === 'color') return a.color;
+ if (RK.avatarVisuals && RK.avatarVisuals.tintColorFor) return RK.avatarVisuals.tintColorFor(source, '#9aa4b2');
+ return '#9aa4b2';
+ }
+
+ function isoCharacterForThumb(a, draft) {
+ var source = {};
+ var d = draft || {};
+ for (var dk in d) source[dk] = d[dk];
+ source.avatar = a.id;
+ if (RK.avatarVisuals && RK.avatarVisuals.resolve) {
+ var visual = RK.avatarVisuals.resolve(source, { projection: 'iso', context: 'customizer' });
+ if (visual && visual.character) return visual.character;
+ }
+ var chars = RK.isoAssets && RK.isoAssets.characters;
+ return (chars && (chars[a.id] || chars.fallback)) || (RK.isoAssets && RK.isoAssets.character) || null;
+ }
+
+ function imageBounds(img) {
+ var key = img && img.src;
+ if (!img || !key) return null;
+ if (thumbBounds[key]) return thumbBounds[key];
+ var w = img.naturalWidth || img.width;
+ var h = img.naturalHeight || img.height;
+ var cv = document.createElement('canvas');
+ cv.width = w;
+ cv.height = h;
+ var ctx = cv.getContext('2d');
+ ctx.drawImage(img, 0, 0);
+ var data = ctx.getImageData(0, 0, w, h).data;
+ var minX = w, minY = h, maxX = -1, maxY = -1;
+ for (var y = 0; y < h; y++) {
+ for (var x = 0; x < w; x++) {
+ if (data[(y * w + x) * 4 + 3] < 8) continue;
+ if (x < minX) minX = x;
+ if (y < minY) minY = y;
+ if (x > maxX) maxX = x;
+ if (y > maxY) maxY = y;
+ }
+ }
+ thumbBounds[key] = maxX < minX ? { x: 0, y: 0, w: w, h: h } : { x: minX, y: minY, w: maxX - minX + 1, h: maxY - minY + 1 };
+ return thumbBounds[key];
+ }
+
+ function drawTintedImage(ctx, img, bounds, x, y, w, h, tint) {
+ bounds = bounds || { x: 0, y: 0, w: img.naturalWidth || img.width, h: img.naturalHeight || img.height };
+ if (!tint) {
+ ctx.drawImage(img, bounds.x, bounds.y, bounds.w, bounds.h, x, y, w, h);
+ return;
+ }
+ var cv = document.createElement('canvas');
+ cv.width = bounds.w;
+ cv.height = bounds.h;
+ var tctx = cv.getContext('2d');
+ tctx.drawImage(img, bounds.x, bounds.y, bounds.w, bounds.h, 0, 0, bounds.w, bounds.h);
+ tctx.globalCompositeOperation = 'source-atop';
+ tctx.globalAlpha = 0.42;
+ tctx.fillStyle = tint;
+ tctx.fillRect(0, 0, cv.width, cv.height);
+ tctx.globalAlpha = 1;
+ tctx.globalCompositeOperation = 'source-over';
+ ctx.drawImage(cv, x, y, w, h);
+ }
+
+ function drawProjectionThumb(ctx, a, draft, projection, onReady) {
+ var color = tintColorForThumb(a, draft);
ctx.clearRect(0, 0, 72, 80);
+ if (projection === 'ascii') {
+ ctx.fillStyle = color || '#9aa4b2';
+ ctx.font = '42px monospace';
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText('@', 36, 43);
+ return;
+ }
+ if (projection === 'iso') {
+ ctx.imageSmoothingEnabled = true;
+ ctx.fillStyle = '#705842';
+ ctx.beginPath();
+ ctx.moveTo(36, 54);
+ ctx.lineTo(62, 42);
+ ctx.lineTo(36, 30);
+ ctx.lineTo(10, 42);
+ ctx.closePath();
+ ctx.fill();
+ ctx.strokeStyle = 'rgba(255,255,255,0.22)';
+ ctx.stroke();
+ var ch = isoCharacterForThumb(a, draft);
+ var rec = loadThumbImage(ch && ch.idle, onReady);
+ if (rec && rec.ready) {
+ var b = imageBounds(rec.img);
+ var dh = 52;
+ var dw = dh * (b.w / b.h);
+ drawTintedImage(ctx, rec.img, b, 36 - dw / 2, 74 - dh, dw, dh, color);
+ } else {
+ ctx.fillStyle = color || '#9aa4b2';
+ ctx.beginPath();
+ ctx.ellipse(36, 37, 8, 16, 0, 0, Math.PI * 2);
+ ctx.fill();
+ ctx.fillStyle = '#0a0c0f';
+ ctx.fillRect(32, 34, 8, 3);
+ }
+ return;
+ }
+ if (projection === '3d') {
+ ctx.imageSmoothingEnabled = true;
+ ctx.fillStyle = color || '#64748b';
+ ctx.beginPath();
+ ctx.ellipse(36, 45, 17, 24, 0, 0, Math.PI * 2);
+ ctx.fill();
+ ctx.fillStyle = 'rgba(255,255,255,0.28)';
+ ctx.beginPath();
+ ctx.ellipse(29, 34, 6, 9, -0.5, 0, Math.PI * 2);
+ ctx.fill();
+ if (a.kind === 'model3d') {
+ ctx.fillStyle = '#d7dbe0';
+ ctx.font = '15px monospace';
+ ctx.textAlign = 'center';
+ ctx.fillText('3D', 36, 49);
+ }
+ return;
+ }
+ }
+
+ function drawBaseThumb(ctx, a, draft, projection, onReady) {
+ ctx.clearRect(0, 0, 72, 80);
+ if (projection && projection !== 'topdown') {
+ drawProjectionThumb(ctx, a, draft, projection, onReady);
+ return;
+ }
if (a.kind === 'color') {
ctx.beginPath(); ctx.arc(36, 44, 21, 0, Math.PI * 2);
ctx.fillStyle = a.color; ctx.fill();
@@ -163,7 +326,11 @@
cv.width = 72; cv.height = 80;
cv.style.cssText = 'display:block;margin:0 auto;image-rendering:pixelated;';
var ctx = cv.getContext('2d');
- function draw() { drawBaseThumb(ctx, a, getDraft && getDraft(), draw); }
+ function draw() {
+ var d = getDraft && getDraft();
+ var projection = (d && d.__projection) || 'topdown';
+ drawBaseThumb(ctx, a, d, projection, draw);
+ }
draw();
if (redraw) redraw.push(draw);
return cv;
@@ -266,8 +433,7 @@
}
function activeProjection() {
- if (selectedMode === 'iso' || selectedMode === '3d' || selectedMode === 'ascii') return selectedMode;
- return 'topdown';
+ return projectionForMode(selectedMode);
}
function ensureColorDraft() {
@@ -455,7 +621,9 @@
selectedMode = mode.id;
if (RK.saveMode) RK.saveMode(mode.id);
markRenderMode();
+ buildAvatarGrid();
renderEditor();
+ redrawAll();
}
function buildRenderModes() {
@@ -567,26 +735,74 @@
redrawAll();
}
- RK.appearances().forEach(function (a) {
- var card = document.createElement('button');
- var locked = !!(RK.canUseAppearance && !RK.canUseAppearance(a));
- card.type = 'button';
- card.className = 'rk-option-card' + (locked ? ' is-locked' : '');
- if (locked) card.title = 'Premium pack - buy credits to unlock';
- card.appendChild(thumbCanvas(a, function () { return draft; }, redrawers));
- var lab = document.createElement('div');
- lab.className = 'rk-option-label';
- lab.textContent = a.label + (a.premium ? ' *' : '');
- card.appendChild(lab);
- card.onclick = function () { selectAvatar(a); };
- grid.appendChild(card);
- cards[a.id] = card;
- });
+ function visibleAppearances() {
+ var projection = activeProjection();
+ return RK.appearances().filter(function (a) {
+ return appearanceVisibleInProjection(a, projection);
+ });
+ }
+
+ function appearanceForId(list, id) {
+ for (var i = 0; i < list.length; i++) if (list[i].id === id) return list[i];
+ return null;
+ }
+
+ function ensureVisibleAvatar() {
+ var list = visibleAppearances();
+ if (appearanceForId(list, draft.avatar)) return;
+ if (!list.length) return;
+ draft.avatar = list[0].id;
+ if (RK.isChar && RK.isChar(draft.avatar)) ensureCharDraft();
+ else if (draftKind() === 'model3d') {
+ ensureColorDraft();
+ draft.equipment = cloneEquipment(DEFAULT_EQUIPMENT);
+ } else {
+ draft.tint = 'none';
+ draft.equipment = cloneEquipment(DEFAULT_EQUIPMENT);
+ delete draft.colors;
+ }
+ }
+
+ function buildAvatarGrid() {
+ ensureVisibleAvatar();
+ grid.innerHTML = '';
+ cards = {};
+ redrawers = [];
+ visibleAppearances().forEach(function (a) {
+ var card = document.createElement('button');
+ var locked = !!(RK.canUseAppearance && !RK.canUseAppearance(a));
+ card.type = 'button';
+ card.className = 'rk-option-card' + (locked ? ' is-locked' : '');
+ if (locked) card.title = 'Premium pack - buy credits to unlock';
+ card.appendChild(thumbCanvas(a, function () {
+ var d = {};
+ for (var dk in draft) d[dk] = draft[dk];
+ d.__projection = activeProjection();
+ return d;
+ }, redrawers));
+ var lab = document.createElement('div');
+ lab.className = 'rk-option-label';
+ lab.textContent = a.label + (a.premium ? ' *' : '');
+ card.appendChild(lab);
+ card.onclick = function () { selectAvatar(a); };
+ grid.appendChild(card);
+ cards[a.id] = card;
+ });
+ mark();
+ }
function drawPreview() {
pctx.clearRect(0, 0, preview.width, preview.height);
var base = baseAppearance(draft.avatar);
- if (base.kind === 'color') {
+ var projection = activeProjection();
+ if (projection !== 'topdown') {
+ var temp = document.createElement('canvas');
+ temp.width = 72;
+ temp.height = 80;
+ drawProjectionThumb(temp.getContext('2d'), base, draft, projection, redrawAll);
+ pctx.imageSmoothingEnabled = projection !== 'ascii';
+ pctx.drawImage(temp, 0, 0, 72, 80, 21, 12, 108, 120);
+ } else if (base.kind === 'color') {
pctx.beginPath(); pctx.arc(75, 86, 34, 0, Math.PI * 2);
pctx.fillStyle = base.color; pctx.fill();
pctx.lineWidth = 3; pctx.strokeStyle = 'rgba(255,255,255,0.35)'; pctx.stroke();
@@ -610,10 +826,12 @@
pctx.drawImage(rec.img, 0, row * s.frameH, s.frameW, s.frameH, 75 - dw / 2, 158 - dh, dw, dh);
}
} else {
- drawBaseThumb(pctx, base, draft, redrawAll);
+ drawBaseThumb(pctx, base, draft, 'topdown', redrawAll);
}
previewName.textContent = base.label || base.id;
- previewMeta.textContent = base.premium ? 'Premium pack' : (base.kind === 'char' ? 'Customizable' : 'Free');
+ previewMeta.textContent = projection !== 'topdown'
+ ? (projection.toUpperCase() + ' identity')
+ : (base.premium ? 'Premium pack' : (base.kind === 'char' ? 'Customizable' : 'Free'));
}
function redrawAll() {
@@ -638,7 +856,7 @@
document.body.appendChild(wrap);
buildRenderModes();
- mark();
+ buildAvatarGrid();
renderEditor();
redrawAll();
};
diff --git a/html/js/render/isoRenderer.js b/html/js/render/isoRenderer.js
index c9ce08f..2ac375e 100644
--- a/html/js/render/isoRenderer.js
+++ b/html/js/render/isoRenderer.js
@@ -17,6 +17,7 @@
this.ctx = this.canvas.getContext('2d');
this.cache = {};
this.tintCache = {};
+ this.boundsCache = {};
this.last = {};
this.lastScene = null;
this.enabled = !(root.RK && RK.canUsePack && this.assets.pack && !RK.canUsePack(this.assets.pack));
@@ -65,6 +66,40 @@
this.ctx.drawImage(img, cx - w / 2, baseY - h, w, h);
};
+ IsoRenderer.prototype._imageBounds = function (img) {
+ if (!img) return null;
+ var key = img.src || img._rkBoundsKey || null;
+ if (key && this.boundsCache[key]) return this.boundsCache[key];
+ var w = img.naturalWidth || img.width;
+ var h = img.naturalHeight || img.height;
+ var cv = document.createElement('canvas');
+ cv.width = w;
+ cv.height = h;
+ var ctx = cv.getContext('2d');
+ ctx.drawImage(img, 0, 0);
+ var data = ctx.getImageData(0, 0, w, h).data;
+ var minX = w, minY = h, maxX = -1, maxY = -1;
+ for (var y = 0; y < h; y++) {
+ for (var x = 0; x < w; x++) {
+ if (data[(y * w + x) * 4 + 3] < 8) continue;
+ if (x < minX) minX = x;
+ if (y < minY) minY = y;
+ if (x > maxX) maxX = x;
+ if (y > maxY) maxY = y;
+ }
+ }
+ var bounds = maxX < minX ? { x: 0, y: 0, w: w, h: h } : { x: minX, y: minY, w: maxX - minX + 1, h: maxY - minY + 1 };
+ if (key) this.boundsCache[key] = bounds;
+ return bounds;
+ };
+
+ IsoRenderer.prototype._drawSpriteImage = function (img, cx, baseY, h) {
+ var b = this._imageBounds(img);
+ if (!b) return;
+ var w = h * (b.w / b.h);
+ this.ctx.drawImage(img, b.x, b.y, b.w, b.h, cx - w / 2, baseY - h, w, h);
+ };
+
IsoRenderer.prototype._tintedImage = function (img, tint) {
if (!img || !tint) return img;
var key = img.src + '|' + tint;
@@ -80,6 +115,7 @@
ctx.fillRect(0, 0, cv.width, cv.height);
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = 'source-over';
+ cv._rkBoundsKey = key;
this.tintCache[key] = cv;
return cv;
};
@@ -163,7 +199,7 @@
var tint = root.RK && RK.avatarVisuals && RK.avatarVisuals.tintColorFor
? RK.avatarVisuals.tintColorFor(frame.visual && frame.visual.appearance)
: null;
- this._drawImage(this._tintedImage(rec.img, tint), it.sx, it.sy + this.tileH * 0.95, ch.imageW || 74, ch.imageH || 148);
+ this._drawSpriteImage(this._tintedImage(rec.img, tint), it.sx, it.sy + this.tileH * 0.95, ch.imageH || 92);
} else {
ctx.beginPath();
ctx.arc(it.sx, it.sy, 8, 0, Math.PI * 2);
@@ -195,6 +231,7 @@
this.ctx = null;
this.cache = {};
this.tintCache = {};
+ this.boundsCache = {};
this.last = {};
this.lastScene = null;
};
diff --git a/html/js/render/sceneModel.js b/html/js/render/sceneModel.js
index a08bd48..7beabea 100644
--- a/html/js/render/sceneModel.js
+++ b/html/js/render/sceneModel.js
@@ -23,6 +23,7 @@
function sceneFromTavern(state, youId) {
state = state || {};
var layout = state.layout || [];
+ var walkable = state.walkable || null;
var rows = state.rows || layout.length;
var cols = state.cols || (layout[0] ? layout[0].length : 0);
@@ -31,7 +32,9 @@
var srcRow = layout[y] || '';
var row = [];
for (var x = 0; x < cols; x++) {
- row.push(TAVERN_TILE_OF[srcRow[x]] || 'wall');
+ if (layout[y]) row.push(TAVERN_TILE_OF[srcRow[x]] || 'wall');
+ else if (walkable && walkable[y]) row.push(walkable[y][x] ? 'floor' : 'wall');
+ else row.push('wall');
}
grid.push(row);
}
diff --git a/html/tavern.html b/html/tavern.html
index 62b50ad..6cf3c61 100644
--- a/html/tavern.html
+++ b/html/tavern.html
@@ -232,7 +232,11 @@
buildModebar();
setMode(RK.loadMode('tiles'));
// Load the designed room (if the server is using one); re-render when ready.
- if (state.roomUrl) RK.loadRoom(state.roomUrl, function () { draw(); });
+ if (state.roomUrl) RK.loadRoom(state.roomUrl, function (room) {
+ if (room && room.desc && room.desc.walkable) state.walkable = room.desc.walkable;
+ rebuildScene();
+ draw();
+ });
setStatus('You are in the tavern.');
});
@@ -245,6 +249,7 @@
function applyFull(s) {
state.layout = s.layout || [];
+ state.walkable = s.walkable || null;
state.cols = s.cols || (state.layout[0] ? state.layout[0].length : 0);
state.rows = s.rows || state.layout.length;
state.occupants = s.occupants || [];
diff --git a/src/multiplayer/Room.js b/src/multiplayer/Room.js
index 880c3f4..4febcb7 100644
--- a/src/multiplayer/Room.js
+++ b/src/multiplayer/Room.js
@@ -201,6 +201,7 @@ class Room {
cols: this.cols,
rows: this.rows,
layout: this.layout,
+ walkable: this.walkable,
solidOccupants: this.solidOccupants,
roomUrl: this.roomUrl || null
};
diff --git a/src/multiplayer/appearance.js b/src/multiplayer/appearance.js
index a0fe904..a6249d9 100644
--- a/src/multiplayer/appearance.js
+++ b/src/multiplayer/appearance.js
@@ -54,6 +54,10 @@ function isCharAvatar(id) {
return includes(CHAR_AVATARS, id);
}
+function isModel3dAvatar(id) {
+ return includes(MODEL3D_AVATARS, id);
+}
+
function isPremiumAvatar(id) {
return !!AVATAR_PACKS[id];
}
@@ -99,11 +103,20 @@ function normalizeAppearance(input = {}) {
let avatar = input.avatar || input.id || 'default';
if (!isValidAvatar(avatar)) avatar = 'default';
- if (!isCharAvatar(avatar)) {
+ if (!isCharAvatar(avatar) && !isModel3dAvatar(avatar)) {
return { avatar, tint: 'none', equipment: { ...DEFAULT_EQUIPMENT } };
}
const colors = normalizeColors(input.colors, input.tint);
+ if (isModel3dAvatar(avatar)) {
+ return {
+ avatar,
+ tint: colors.base,
+ equipment: { ...DEFAULT_EQUIPMENT },
+ colors
+ };
+ }
+
return {
avatar,
tint: colors.base,
@@ -129,6 +142,7 @@ module.exports = {
avatarPack,
isValidAvatar,
isCharAvatar,
+ isModel3dAvatar,
isPremiumAvatar,
normalizeEquipment,
normalizeColors,
diff --git a/test/appearanceModel3d.test.js b/test/appearanceModel3d.test.js
new file mode 100644
index 0000000..d3effe7
--- /dev/null
+++ b/test/appearanceModel3d.test.js
@@ -0,0 +1,19 @@
+const Appearance = require('../src/multiplayer/appearance');
+
+describe('appearance normalization for 3D avatars', () => {
+ test('preserves base colors for model avatars', () => {
+ const ap = Appearance.normalizeAppearance({
+ avatar: 'kenney-survivor-male',
+ tint: 'gold',
+ colors: { base: 'teal', skin: 'umber', hair: 'silver' },
+ equipment: { body: 'mail', head: 'helm' }
+ });
+
+ expect(ap).toMatchObject({
+ avatar: 'kenney-survivor-male',
+ tint: 'teal',
+ equipment: { body: 'none', head: 'none', shield: 'none', weapon: 'none' },
+ colors: expect.objectContaining({ base: 'teal', skin: 'umber', hair: 'silver' })
+ });
+ });
+});
diff --git a/test/renderPackResolver.test.js b/test/renderPackResolver.test.js
index 74f46c6..4c22709 100644
--- a/test/renderPackResolver.test.js
+++ b/test/renderPackResolver.test.js
@@ -82,7 +82,7 @@ describe('render pack visual resolver', () => {
RK.setEntitlementSnapshot({ totalCreditsPurchased: 1 });
const iso = RK.avatarVisuals.resolve({ avatar: 'char-ranger' }, { projection: 'iso' });
expect(iso).toMatchObject({ projection: 'iso', kind: 'iso', pack: 'iso-dungeon', allowed: true });
- expect(iso.character.idle).toContain('Male_0_Idle0.png');
+ expect(iso.character.idle).toContain('Male_4_Idle0.png');
const compat = RK.resolveAppearance(
{ appearance: { avatar: 'kenney-survivor-female' } },
@@ -95,6 +95,15 @@ describe('render pack visual resolver', () => {
const RK = loadRenderKit();
expect(RK.isoAssets.tiles.floor).toContain('planks_S.png');
expect(RK.isoAssets.tiles.floor).not.toContain('stone_S.png');
+ expect(RK.isoAssets.tiles.wall).toContain('stoneWallHalf_S.png');
+ });
+
+ test('iso pack exposes only real imported character variants', () => {
+ const RK = loadRenderKit();
+ expect(RK.isoAssets.characters['char-villager'].idle).toContain('Male_0_Idle0.png');
+ expect(RK.isoAssets.characters['char-merchant'].idle).toContain('Male_7_Idle0.png');
+ expect(RK.isoAssets.characters['char-wizard']).toBeUndefined();
+ expect(RK.isoAssets.characters['char-goblin']).toBeUndefined();
});
test('projection visuals expose the saved base tint as a render color', () => {
diff --git a/test/renderScene.test.js b/test/renderScene.test.js
index 751bcc0..eabf450 100644
--- a/test/renderScene.test.js
+++ b/test/renderScene.test.js
@@ -35,4 +35,21 @@ describe('sceneFromTavern (render kit adapter)', () => {
const s = scene.sceneFromTavern({ cols: 2, rows: 1, layout: ['?~'], occupants: [] });
expect(s.grid[0]).toEqual(['wall', 'wall']);
});
+
+ test('uses walkability when a designed room has no ASCII layout', () => {
+ const s = scene.sceneFromTavern({
+ cols: 3,
+ rows: 2,
+ layout: null,
+ walkable: [
+ [true, false, true],
+ [false, true, true]
+ ],
+ occupants: []
+ });
+ expect(s.grid).toEqual([
+ ['floor', 'wall', 'floor'],
+ ['wall', 'floor', 'floor']
+ ]);
+ });
});
diff --git a/test/tavernRoom.test.js b/test/tavernRoom.test.js
index 73e17d2..cb4d7d6 100644
--- a/test/tavernRoom.test.js
+++ b/test/tavernRoom.test.js
@@ -23,6 +23,20 @@ describe('Room — shared real-time engine (Tavern instance)', () => {
expect(ids).toEqual(['alice', 'bob']);
});
+ test('full state includes walkability for designed rooms without ASCII layout', () => {
+ const room = new Room({
+ id: 'designed',
+ roomData: {
+ cols: 2,
+ rows: 2,
+ walkable: [[true, false], [false, true]]
+ }
+ });
+ const state = room.fullState();
+ expect(state.layout).toBeNull();
+ expect(state.walkable).toEqual([[true, false], [false, true]]);
+ });
+
test('server-authoritative movement: a valid step moves and sets facing', () => {
const room = new Room({ id: 'r' });
const occ = room.addOccupant('alice');