Compare commits
3 Commits
eeebed10c0
...
23b43a6f2a
| Author | SHA1 | Date |
|---|---|---|
|
|
23b43a6f2a | |
|
|
02e0e70b99 | |
|
|
ada2535b62 |
|
|
@ -0,0 +1,167 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Process new puzzle images end-to-end:
|
||||
# 1. Rename files in prep/ to lowercase with underscores
|
||||
# 2. Move them to puzzles/
|
||||
# 3. Generate thumbnails for any images missing one
|
||||
# 4. Sync puzzles.json and thumbnails.json
|
||||
#
|
||||
# Run from: assets/images/
|
||||
# Requires: ImageMagick (convert command)
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PREP_DIR="prep"
|
||||
PUZZLE_DIR="puzzles"
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
PUZZLES_JSON="$REPO_ROOT/assets/puzzles.json"
|
||||
THUMBS_JSON="$REPO_ROOT/assets/thumbnails.json"
|
||||
THUMB_WIDTH=576
|
||||
THUMB_HEIGHT=324
|
||||
|
||||
# ─── 1. Rename files in prep/ ──────────────────────────────────────────
|
||||
|
||||
echo "=== Step 1: Renaming files in $PREP_DIR/ ==="
|
||||
renamed=0
|
||||
for f in "$PREP_DIR"/*.png "$PREP_DIR"/*.jpg "$PREP_DIR"/*.jpeg; do
|
||||
[ -f "$f" ] || continue
|
||||
dir=$(dirname "$f")
|
||||
base=$(basename "$f")
|
||||
newname=$(echo "$base" | tr '[:upper:]' '[:lower:]' | tr ' ' '_')
|
||||
if [ "$base" != "$newname" ]; then
|
||||
mv "$f" "$dir/$newname"
|
||||
echo " Renamed: $base -> $newname"
|
||||
renamed=$((renamed + 1))
|
||||
fi
|
||||
done
|
||||
echo " Renamed $renamed file(s)"
|
||||
|
||||
# ─── 2. Move files from prep/ to puzzles/ ──────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "=== Step 2: Moving images from $PREP_DIR/ to $PUZZLE_DIR/ ==="
|
||||
moved=0
|
||||
for f in "$PREP_DIR"/*.png "$PREP_DIR"/*.jpg "$PREP_DIR"/*.jpeg; do
|
||||
[ -f "$f" ] || continue
|
||||
base=$(basename "$f")
|
||||
# Skip shell scripts
|
||||
case "$base" in *.sh) continue ;; esac
|
||||
if [ -f "$PUZZLE_DIR/$base" ]; then
|
||||
echo " SKIP $base (already exists in $PUZZLE_DIR/)"
|
||||
else
|
||||
mv "$f" "$PUZZLE_DIR/$base"
|
||||
echo " Moved: $base"
|
||||
moved=$((moved + 1))
|
||||
fi
|
||||
done
|
||||
echo " Moved $moved file(s)"
|
||||
|
||||
# ─── 3. Generate thumbnails ────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "=== Step 3: Generating thumbnails ==="
|
||||
|
||||
if ! command -v convert &> /dev/null; then
|
||||
echo "Error: ImageMagick is not installed."
|
||||
echo " Ubuntu/Debian: sudo apt install imagemagick"
|
||||
echo " macOS: brew install imagemagick"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
created=0
|
||||
skipped=0
|
||||
for file in "$PUZZLE_DIR"/*; do
|
||||
[ -f "$file" ] || continue
|
||||
base=$(basename "$file")
|
||||
# Skip thumbnails, scripts
|
||||
case "$base" in
|
||||
thumb_*|*.sh) continue ;;
|
||||
esac
|
||||
# Check it's actually an image
|
||||
mime=$(file --mime-type -b "$file")
|
||||
case "$mime" in
|
||||
image/*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
|
||||
thumb="$PUZZLE_DIR/thumb_${base}"
|
||||
if [ -f "$thumb" ]; then
|
||||
skipped=$((skipped + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
convert "$file" -resize "${THUMB_WIDTH}x${THUMB_HEIGHT}!" -strip "$thumb"
|
||||
echo " Created: thumb_${base}"
|
||||
created=$((created + 1))
|
||||
done
|
||||
echo " Created $created thumbnail(s), skipped $skipped existing"
|
||||
|
||||
# ─── 4. Sync JSON manifests ────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "=== Step 4: Syncing JSON manifests ==="
|
||||
|
||||
puzzles="["
|
||||
thumbs="["
|
||||
first=true
|
||||
|
||||
for img in "$PUZZLE_DIR"/*.png "$PUZZLE_DIR"/*.jpg "$PUZZLE_DIR"/*.jpeg; do
|
||||
[ -f "$img" ] || continue
|
||||
base=$(basename "$img")
|
||||
ext="${base##*.}"
|
||||
name="${base%.*}"
|
||||
|
||||
# Skip thumbnails
|
||||
[[ "$name" == thumb_* ]] && continue
|
||||
|
||||
# Derive keys (replace hyphens with underscores)
|
||||
safe="${name//-/_}"
|
||||
puzzle_key="puzzle_${safe}"
|
||||
thumb_key="thumb_${safe}"
|
||||
thumb_file="$PUZZLE_DIR/thumb_${name}.${ext}"
|
||||
|
||||
# Skip if no matching thumbnail
|
||||
if [ ! -f "$thumb_file" ]; then
|
||||
echo " WARNING: No thumbnail for $name — skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Build label: replace underscores/hyphens with spaces, then title-case
|
||||
label=$(echo "$name" | sed 's/[_-]/ /g' | sed 's/\b\(.\)/\u\1/g')
|
||||
|
||||
# Paths relative to repo root
|
||||
rel_img="assets/images/puzzles/${base}"
|
||||
rel_thumb="assets/images/puzzles/thumb_${name}.${ext}"
|
||||
|
||||
sep=""
|
||||
$first || sep=","
|
||||
first=false
|
||||
|
||||
puzzles+="${sep}
|
||||
{
|
||||
\"key\": \"${puzzle_key}\",
|
||||
\"path\": \"${rel_img}\",
|
||||
\"label\": \"${label}\"
|
||||
}"
|
||||
|
||||
thumbs+="${sep}
|
||||
{
|
||||
\"key\": \"${thumb_key}\",
|
||||
\"path\": \"${rel_thumb}\",
|
||||
\"puzzleKey\": \"${puzzle_key}\"
|
||||
}"
|
||||
done
|
||||
|
||||
puzzles+="
|
||||
]"
|
||||
thumbs+="
|
||||
]"
|
||||
|
||||
echo "$puzzles" > "$PUZZLES_JSON"
|
||||
echo "$thumbs" > "$THUMBS_JSON"
|
||||
|
||||
echo " Updated puzzles.json ($(grep -c '"key"' "$PUZZLES_JSON") entries)"
|
||||
echo " Updated thumbnails.json ($(grep -c '"key"' "$THUMBS_JSON") entries)"
|
||||
echo ""
|
||||
echo "=== Done! ==="
|
||||
|
After Width: | Height: | Size: 2.7 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 4.3 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 4.2 MiB |
|
After Width: | Height: | Size: 307 KiB |
|
After Width: | Height: | Size: 349 KiB |
|
After Width: | Height: | Size: 261 KiB |
|
After Width: | Height: | Size: 319 KiB |
|
After Width: | Height: | Size: 362 KiB |
|
After Width: | Height: | Size: 336 KiB |
|
After Width: | Height: | Size: 325 KiB |
|
After Width: | Height: | Size: 363 KiB |
|
After Width: | Height: | Size: 295 KiB |
|
After Width: | Height: | Size: 323 KiB |
|
|
@ -44,6 +44,11 @@
|
|||
"path": "assets/images/puzzles/cottages_on_the_street.png",
|
||||
"label": "Cottages On The Street"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_cownappers",
|
||||
"path": "assets/images/puzzles/cownappers.png",
|
||||
"label": "Cownappers"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_dwarven_blacksmith",
|
||||
"path": "assets/images/puzzles/dwarven_blacksmith.png",
|
||||
|
|
@ -69,6 +74,11 @@
|
|||
"path": "assets/images/puzzles/floating_wizards_village.png",
|
||||
"label": "Floating Wizards Village"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_forest_conjurer",
|
||||
"path": "assets/images/puzzles/forest_conjurer.png",
|
||||
"label": "Forest Conjurer"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_four_seasons_2",
|
||||
"path": "assets/images/puzzles/four_seasons_2.png",
|
||||
|
|
@ -84,6 +94,11 @@
|
|||
"path": "assets/images/puzzles/fuzzy_halloween.png",
|
||||
"label": "Fuzzy Halloween"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_germanic_castle",
|
||||
"path": "assets/images/puzzles/germanic_castle.png",
|
||||
"label": "Germanic Castle"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_golden_in_the_mountains",
|
||||
"path": "assets/images/puzzles/golden_in_the_mountains.png",
|
||||
|
|
@ -114,6 +129,11 @@
|
|||
"path": "assets/images/puzzles/home_sweet_home.png",
|
||||
"label": "Home Sweet Home"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_hong_kong_phonecall",
|
||||
"path": "assets/images/puzzles/hong_kong_phonecall.png",
|
||||
"label": "Hong Kong Phonecall"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_jeweled_frogs",
|
||||
"path": "assets/images/puzzles/jeweled_frogs.png",
|
||||
|
|
@ -129,6 +149,11 @@
|
|||
"path": "assets/images/puzzles/lake_treehouse.png",
|
||||
"label": "Lake Treehouse"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_lonely_robot_2",
|
||||
"path": "assets/images/puzzles/lonely_robot_2.png",
|
||||
"label": "Lonely Robot 2"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_lone_ship_in_the_seas",
|
||||
"path": "assets/images/puzzles/lone_ship_in_the_seas.png",
|
||||
|
|
@ -159,6 +184,21 @@
|
|||
"path": "assets/images/puzzles/mountain_blanket.png",
|
||||
"label": "Mountain Blanket"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_mushroom_world",
|
||||
"path": "assets/images/puzzles/mushroom_world.png",
|
||||
"label": "Mushroom World"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_octomech_2",
|
||||
"path": "assets/images/puzzles/octomech_2.png",
|
||||
"label": "Octomech 2"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_old_polish_town",
|
||||
"path": "assets/images/puzzles/old_polish_town.png",
|
||||
"label": "Old Polish Town"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_opulant_flowers",
|
||||
"path": "assets/images/puzzles/opulant_flowers.png",
|
||||
|
|
@ -169,6 +209,11 @@
|
|||
"path": "assets/images/puzzles/orc_and_the_undead.png",
|
||||
"label": "Orc And The Undead"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_red_eyes",
|
||||
"path": "assets/images/puzzles/red_eyes.png",
|
||||
"label": "Red Eyes"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_red_panda_in_the_bamboo_forest",
|
||||
"path": "assets/images/puzzles/red_panda_in_the_bamboo_forest.png",
|
||||
|
|
@ -204,6 +249,11 @@
|
|||
"path": "assets/images/puzzles/the_disassembled_android.png",
|
||||
"label": "The Disassembled Android"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_the_mall_interior",
|
||||
"path": "assets/images/puzzles/the_mall_interior.png",
|
||||
"label": "The Mall Interior"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_the_old_w0rm",
|
||||
"path": "assets/images/puzzles/the_old_w0rm.png",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@
|
|||
"path": "assets/images/puzzles/thumb_cottages_on_the_street.png",
|
||||
"puzzleKey": "puzzle_cottages_on_the_street"
|
||||
},
|
||||
{
|
||||
"key": "thumb_cownappers",
|
||||
"path": "assets/images/puzzles/thumb_cownappers.png",
|
||||
"puzzleKey": "puzzle_cownappers"
|
||||
},
|
||||
{
|
||||
"key": "thumb_dwarven_blacksmith",
|
||||
"path": "assets/images/puzzles/thumb_dwarven_blacksmith.png",
|
||||
|
|
@ -69,6 +74,11 @@
|
|||
"path": "assets/images/puzzles/thumb_floating_wizards_village.png",
|
||||
"puzzleKey": "puzzle_floating_wizards_village"
|
||||
},
|
||||
{
|
||||
"key": "thumb_forest_conjurer",
|
||||
"path": "assets/images/puzzles/thumb_forest_conjurer.png",
|
||||
"puzzleKey": "puzzle_forest_conjurer"
|
||||
},
|
||||
{
|
||||
"key": "thumb_four_seasons_2",
|
||||
"path": "assets/images/puzzles/thumb_four_seasons_2.png",
|
||||
|
|
@ -84,6 +94,11 @@
|
|||
"path": "assets/images/puzzles/thumb_fuzzy_halloween.png",
|
||||
"puzzleKey": "puzzle_fuzzy_halloween"
|
||||
},
|
||||
{
|
||||
"key": "thumb_germanic_castle",
|
||||
"path": "assets/images/puzzles/thumb_germanic_castle.png",
|
||||
"puzzleKey": "puzzle_germanic_castle"
|
||||
},
|
||||
{
|
||||
"key": "thumb_golden_in_the_mountains",
|
||||
"path": "assets/images/puzzles/thumb_golden_in_the_mountains.png",
|
||||
|
|
@ -114,6 +129,11 @@
|
|||
"path": "assets/images/puzzles/thumb_home_sweet_home.png",
|
||||
"puzzleKey": "puzzle_home_sweet_home"
|
||||
},
|
||||
{
|
||||
"key": "thumb_hong_kong_phonecall",
|
||||
"path": "assets/images/puzzles/thumb_hong_kong_phonecall.png",
|
||||
"puzzleKey": "puzzle_hong_kong_phonecall"
|
||||
},
|
||||
{
|
||||
"key": "thumb_jeweled_frogs",
|
||||
"path": "assets/images/puzzles/thumb_jeweled_frogs.png",
|
||||
|
|
@ -129,6 +149,11 @@
|
|||
"path": "assets/images/puzzles/thumb_lake_treehouse.png",
|
||||
"puzzleKey": "puzzle_lake_treehouse"
|
||||
},
|
||||
{
|
||||
"key": "thumb_lonely_robot_2",
|
||||
"path": "assets/images/puzzles/thumb_lonely_robot_2.png",
|
||||
"puzzleKey": "puzzle_lonely_robot_2"
|
||||
},
|
||||
{
|
||||
"key": "thumb_lone_ship_in_the_seas",
|
||||
"path": "assets/images/puzzles/thumb_lone_ship_in_the_seas.png",
|
||||
|
|
@ -159,6 +184,21 @@
|
|||
"path": "assets/images/puzzles/thumb_mountain_blanket.png",
|
||||
"puzzleKey": "puzzle_mountain_blanket"
|
||||
},
|
||||
{
|
||||
"key": "thumb_mushroom_world",
|
||||
"path": "assets/images/puzzles/thumb_mushroom_world.png",
|
||||
"puzzleKey": "puzzle_mushroom_world"
|
||||
},
|
||||
{
|
||||
"key": "thumb_octomech_2",
|
||||
"path": "assets/images/puzzles/thumb_octomech_2.png",
|
||||
"puzzleKey": "puzzle_octomech_2"
|
||||
},
|
||||
{
|
||||
"key": "thumb_old_polish_town",
|
||||
"path": "assets/images/puzzles/thumb_old_polish_town.png",
|
||||
"puzzleKey": "puzzle_old_polish_town"
|
||||
},
|
||||
{
|
||||
"key": "thumb_opulant_flowers",
|
||||
"path": "assets/images/puzzles/thumb_opulant_flowers.png",
|
||||
|
|
@ -169,6 +209,11 @@
|
|||
"path": "assets/images/puzzles/thumb_orc_and_the_undead.png",
|
||||
"puzzleKey": "puzzle_orc_and_the_undead"
|
||||
},
|
||||
{
|
||||
"key": "thumb_red_eyes",
|
||||
"path": "assets/images/puzzles/thumb_red_eyes.png",
|
||||
"puzzleKey": "puzzle_red_eyes"
|
||||
},
|
||||
{
|
||||
"key": "thumb_red_panda_in_the_bamboo_forest",
|
||||
"path": "assets/images/puzzles/thumb_red_panda_in_the_bamboo_forest.png",
|
||||
|
|
@ -204,6 +249,11 @@
|
|||
"path": "assets/images/puzzles/thumb_the_disassembled_android.png",
|
||||
"puzzleKey": "puzzle_the_disassembled_android"
|
||||
},
|
||||
{
|
||||
"key": "thumb_the_mall_interior",
|
||||
"path": "assets/images/puzzles/thumb_the_mall_interior.png",
|
||||
"puzzleKey": "puzzle_the_mall_interior"
|
||||
},
|
||||
{
|
||||
"key": "thumb_the_old_w0rm",
|
||||
"path": "assets/images/puzzles/thumb_the_old_w0rm.png",
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@ class PuzzleScene extends Phaser.Scene {
|
|||
if (!this.cache.audio.exists('sfx_grab')) {
|
||||
this.load.audio('sfx_grab', 'assets/audio/fx/grab.mp3');
|
||||
}
|
||||
if (!this.cache.audio.exists('sfx_stats')) {
|
||||
this.load.audio('sfx_stats', 'assets/audio/fx/stats.mp3');
|
||||
}
|
||||
|
||||
// Music track list
|
||||
if (!this.cache.json.exists('music_tracks')) {
|
||||
|
|
@ -365,7 +368,7 @@ class PuzzleScene extends Phaser.Scene {
|
|||
|
||||
this._edgeIds = this._pieces
|
||||
.filter(p => p.edges.top === 'flat' || p.edges.bottom === 'flat' ||
|
||||
p.edges.left === 'flat' || p.edges.right === 'flat')
|
||||
p.edges.left === 'flat' || p.edges.right === 'flat')
|
||||
.map(p => p.id);
|
||||
|
||||
const midCol = Math.ceil(this._cols / 2);
|
||||
|
|
@ -1172,6 +1175,16 @@ class PuzzleScene extends Phaser.Scene {
|
|||
if (po.image.texture.key !== expectedKey && this.textures.exists(expectedKey)) {
|
||||
po.image.setTexture(expectedKey);
|
||||
}
|
||||
|
||||
// Contour-following drop shadow via preFX (Phaser 3.60+)
|
||||
if (po.image.preFX) {
|
||||
if (!isMerged && !po._shadowFX) {
|
||||
po._shadowFX = po.image.preFX.addShadow(2, 2, 0.06, 1, 0x000000, 6);
|
||||
} else if (isMerged && po._shadowFX) {
|
||||
po.image.preFX.remove(po._shadowFX);
|
||||
po._shadowFX = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -1218,7 +1231,7 @@ class PuzzleScene extends Phaser.Scene {
|
|||
if (!this._glowingPieceIds) this._glowingPieceIds = new Set();
|
||||
if (!this._glowTimers) this._glowTimers = new Map();
|
||||
|
||||
const GLOW_DELAY = 500; // ms a neighbor must stay in range before glow appears
|
||||
const GLOW_DELAY = 700; // ms a neighbor must stay in range before glow appears
|
||||
const now = Date.now();
|
||||
|
||||
// Track which neighbors are in proximity this frame
|
||||
|
|
@ -1254,8 +1267,8 @@ class PuzzleScene extends Phaser.Scene {
|
|||
[
|
||||
[20, 0.06],
|
||||
[14, 0.12],
|
||||
[8, 0.30],
|
||||
[4, 0.70],
|
||||
[8, 0.30],
|
||||
[4, 0.70],
|
||||
].forEach(([baseLW, baseAlpha]) => {
|
||||
const lw = Math.max(1, baseLW * intensity);
|
||||
const alpha = baseAlpha * intensity;
|
||||
|
|
@ -2166,9 +2179,9 @@ class PuzzleScene extends Phaser.Scene {
|
|||
if (!this._uiLayer) return;
|
||||
const rect = this.sys.game.canvas.getBoundingClientRect();
|
||||
Object.assign(this._uiLayer.style, {
|
||||
left: rect.left + 'px',
|
||||
top: rect.top + 'px',
|
||||
transform: `scale(${rect.width / 1920}, ${rect.height / 1080})`,
|
||||
left: rect.left + 'px',
|
||||
top: rect.top + 'px',
|
||||
transform: `scale(${rect.width / 1920}, ${rect.height / 1080})`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -2178,13 +2191,13 @@ class PuzzleScene extends Phaser.Scene {
|
|||
// except on the interactive children.
|
||||
this._uiLayer = document.createElement('div');
|
||||
Object.assign(this._uiLayer.style, {
|
||||
position: 'fixed',
|
||||
width: '1920px',
|
||||
height: '1080px',
|
||||
position: 'fixed',
|
||||
width: '1920px',
|
||||
height: '1080px',
|
||||
transformOrigin: 'top left',
|
||||
pointerEvents: 'none',
|
||||
zIndex: '10',
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
pointerEvents: 'none',
|
||||
zIndex: '10',
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
});
|
||||
document.body.appendChild(this._uiLayer);
|
||||
this._syncOverlayToCanvas();
|
||||
|
|
@ -2801,11 +2814,13 @@ class PuzzleScene extends Phaser.Scene {
|
|||
const typeNext = () => {
|
||||
if (this._completionOverlay === null) {
|
||||
clearInterval(cursorBlink);
|
||||
if (this._statsSound) { this._statsSound.stop(); this._statsSound.destroy(); this._statsSound = null; }
|
||||
return;
|
||||
}
|
||||
|
||||
if (lineIdx >= lines.length) {
|
||||
// Done — keep cursor blinking at end
|
||||
// Done — stop stats sound, keep cursor blinking at end
|
||||
if (this._statsSound) { this._statsSound.stop(); this._statsSound.destroy(); this._statsSound = null; }
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2845,7 +2860,9 @@ class PuzzleScene extends Phaser.Scene {
|
|||
}
|
||||
};
|
||||
|
||||
// Start typing after a short delay
|
||||
// Start stats sound loop and typing after a short delay
|
||||
this._statsSound = this.sound.add('sfx_stats', { loop: true, volume: 0.5 });
|
||||
this._statsSound.play();
|
||||
setTimeout(typeNext, 500);
|
||||
}
|
||||
|
||||
|
|
|
|||