mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
327c48aa1a | ||
|
|
3a18a507c0 | ||
|
|
2769503899 | ||
|
|
e719119764 | ||
|
|
174f322696 | ||
|
|
33125c6322 | ||
|
|
e97bd5bd4c | ||
|
|
88acfe5e5b | ||
|
|
73abcddf44 | ||
|
|
7ca8ff8c38 | ||
|
|
22778dbd3d | ||
|
|
d70e734661 | ||
|
|
2c09360bfd | ||
|
|
58d7043a50 | ||
|
|
27c58cc97e | ||
|
|
20c1f1141e | ||
|
|
4844792aaa | ||
|
|
201b37dda0 | ||
|
|
77886d34cb | ||
|
|
74080634de | ||
|
|
f7ab62ab1d | ||
|
|
5c7e759385 |
266
.github/workflows/python-app.yml
vendored
266
.github/workflows/python-app.yml
vendored
@@ -1,143 +1,159 @@
|
|||||||
name: PyTaiko
|
name: PyTaiko
|
||||||
on:
|
on:
|
||||||
push:
|
workflow_dispatch:
|
||||||
branches: ["main"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["main"]
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
issues: write
|
issues: write
|
||||||
repository-projects: write
|
repository-projects: write
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-22.04, windows-latest]
|
os: [ubuntu-22.04, windows-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check-out repository
|
- name: Check-out repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install libaudio Dependencies (macOS)
|
- name: Install libaudio Dependencies (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
brew update
|
brew update
|
||||||
brew install portaudio libsndfile speexdsp ccache
|
brew install portaudio libsndfile speexdsp ccache
|
||||||
|
|
||||||
- name: Install libaudio Dependencies (Windows)
|
- name: Install libaudio Dependencies (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
with:
|
with:
|
||||||
update: true
|
update: true
|
||||||
install: >-
|
install: >-
|
||||||
base-devel
|
base-devel
|
||||||
mingw-w64-x86_64-gcc
|
mingw-w64-x86_64-gcc
|
||||||
mingw-w64-x86_64-libsndfile
|
mingw-w64-x86_64-libsndfile
|
||||||
mingw-w64-x86_64-speexdsp
|
mingw-w64-x86_64-speexdsp
|
||||||
mingw-w64-x86_64-ccache
|
mingw-w64-x86_64-ccache
|
||||||
|
|
||||||
- name: Install libaudio Dependencies (Linux)
|
- name: Install libaudio Dependencies (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y \
|
sudo apt-get install -y \
|
||||||
build-essential \
|
build-essential \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
libsndfile1-dev \
|
libsndfile1-dev \
|
||||||
libspeexdsp-dev \
|
libspeexdsp-dev \
|
||||||
portaudio19-dev \
|
portaudio19-dev \
|
||||||
libpulse-dev \
|
libpulse-dev \
|
||||||
ccache \
|
ccache \
|
||||||
|
|
||||||
- name: Build libaudio (Windows)
|
- name: Build libaudio (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cd libs/audio
|
cd libs/audio
|
||||||
make clean
|
make clean
|
||||||
make all
|
make all
|
||||||
make verify
|
make verify
|
||||||
|
|
||||||
- name: Build libaudio (Unix)
|
- name: Build libaudio (Unix)
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cd libs/audio
|
cd libs/audio
|
||||||
make clean
|
make clean
|
||||||
make all
|
make all
|
||||||
make verify
|
make verify
|
||||||
|
|
||||||
- name: Upload libaudio Artifacts
|
- name: Upload libaudio Artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: libaudio-${{ runner.os }}-${{ runner.arch }}
|
name: libaudio-${{ runner.os }}-${{ runner.arch }}
|
||||||
path: |
|
path: |
|
||||||
libs/audio/libaudio.dll
|
libs/audio/libaudio.dll
|
||||||
libs/audio/libaudio.so
|
libs/audio/libaudio.so
|
||||||
libs/audio/libaudio.dylib
|
libs/audio/libaudio.dylib
|
||||||
libs/audio/*.a
|
libs/audio/*.a
|
||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
|
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@v4
|
uses: astral-sh/setup-uv@v4
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
run: uv python install
|
run: uv python install
|
||||||
|
|
||||||
- name: Build Executable
|
- name: Build Executable
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
uv run nuitka \
|
uv run nuitka \
|
||||||
--lto=yes \
|
--lto=yes \
|
||||||
--mode=app \
|
--mode=app \
|
||||||
--noinclude-setuptools-mode=nofollow \
|
--noinclude-setuptools-mode=nofollow \
|
||||||
--noinclude-IPython-mode=nofollow \
|
--noinclude-IPython-mode=nofollow \
|
||||||
--assume-yes-for-downloads \
|
--assume-yes-for-downloads \
|
||||||
--windows-icon-from-ico=libs/icon.ico \
|
--windows-icon-from-ico=libs/icon.ico \
|
||||||
--macos-app-icon=libs/icon.icns \
|
--macos-app-icon=libs/icon.icns \
|
||||||
--linux-icon=libs/icon.png \
|
--linux-icon=libs/icon.png \
|
||||||
PyTaiko.py
|
PyTaiko.py
|
||||||
|
|
||||||
- name: Create Release Directory
|
- name: Create Release Directory
|
||||||
run: |
|
run: |
|
||||||
mkdir -p release
|
mkdir -p release
|
||||||
cp -r Skins Songs config.toml shader model release/
|
cp -r Skins Songs config.toml shader model release/
|
||||||
|
|
||||||
if [ "${{ runner.os }}" == "Windows" ]; then
|
if [ "${{ runner.os }}" == "Windows" ]; then
|
||||||
cp libs/audio/*.dll release/ 2>/dev/null || echo "libaudio not found"
|
cp libs/audio/*.dll release/ 2>/dev/null || echo "libaudio not found"
|
||||||
elif [ "${{ runner.os }}" == "macOS" ]; then
|
elif [ "${{ runner.os }}" == "macOS" ]; then
|
||||||
cp libs/audio/libaudio.dylib release/ 2>/dev/null || echo "libaudio not found"
|
cp libs/audio/libaudio.dylib release/ 2>/dev/null || echo "libaudio not found"
|
||||||
else
|
else
|
||||||
cp libs/audio/libaudio.so release/ 2>/dev/null || echo "libaudio not found"
|
cp libs/audio/libaudio.so release/ 2>/dev/null || echo "libaudio not found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${{ runner.os }}" == "Windows" ]; then
|
if [ "${{ runner.os }}" == "Windows" ]; then
|
||||||
cp *.exe release/ 2>/dev/null || echo "No .exe files found"
|
cp *.exe release/ 2>/dev/null || echo "No .exe files found"
|
||||||
elif [ "${{ runner.os }}" == "macOS" ]; then
|
elif [ "${{ runner.os }}" == "macOS" ]; then
|
||||||
cp -r *.app release/ 2>/dev/null || echo "No .app bundles found"
|
cp -r *.app release/ 2>/dev/null || echo "No .app bundles found"
|
||||||
else
|
else
|
||||||
cp *.bin release/ 2>/dev/null || echo "No .bin files found"
|
cp *.bin release/ 2>/dev/null || echo "No .bin files found"
|
||||||
fi
|
fi
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Create Zip Archive
|
- name: Create Zip Archive
|
||||||
run: |
|
run: |
|
||||||
cd release
|
cd release
|
||||||
if [ "${{ runner.os }}" == "Windows" ]; then
|
if [ "${{ runner.os }}" == "Windows" ]; then
|
||||||
7z a ../PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip *
|
7z a ../PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip *
|
||||||
else
|
else
|
||||||
zip -r ../PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip *
|
zip -r ../PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip *
|
||||||
fi
|
fi
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Upload Release
|
- name: Upload Build Artifacts
|
||||||
uses: softprops/action-gh-release@v2
|
uses: actions/upload-artifact@v4
|
||||||
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
with:
|
||||||
with:
|
name: pytaiko-${{ runner.os }}-${{ runner.arch }}
|
||||||
files: PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip
|
path: PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip
|
||||||
name: "PyTaiko [Rolling Release]"
|
retention-days: 1
|
||||||
tag_name: "latest"
|
|
||||||
make_latest: true
|
release:
|
||||||
env:
|
needs: build
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
steps:
|
||||||
|
- name: Download All Artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
pattern: pytaiko-*
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Upload Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: PyTaiko-*.zip
|
||||||
|
name: "PyTaiko [Rolling Release]"
|
||||||
|
tag_name: "latest"
|
||||||
|
make_latest: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,8 +5,8 @@ cache
|
|||||||
dev-config.toml
|
dev-config.toml
|
||||||
libaudio.so
|
libaudio.so
|
||||||
latest.log
|
latest.log
|
||||||
libaudio.dll
|
|
||||||
libaudio.dylib
|
libaudio.dylib
|
||||||
scores.db
|
scores.db
|
||||||
scores_gen3.db
|
scores_gen3.db
|
||||||
./libs/audio/audio.o
|
./libs/audio/audio.o
|
||||||
|
*.dll
|
||||||
|
|||||||
26
PyTaiko.py
26
PyTaiko.py
@@ -1,12 +1,12 @@
|
|||||||
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
from pypresence.presence import Presence
|
||||||
from raylib.defines import (
|
from raylib.defines import (
|
||||||
RL_FUNC_ADD,
|
RL_FUNC_ADD,
|
||||||
RL_ONE,
|
RL_ONE,
|
||||||
@@ -15,6 +15,7 @@ from raylib.defines import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
|
from libs.config import get_config
|
||||||
from libs.global_data import PlayerNum, ScoreMethod
|
from libs.global_data import PlayerNum, ScoreMethod
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
from libs.song_hash import DB_VERSION
|
from libs.song_hash import DB_VERSION
|
||||||
@@ -23,27 +24,24 @@ from libs.utils import (
|
|||||||
force_dedicated_gpu,
|
force_dedicated_gpu,
|
||||||
get_current_ms,
|
get_current_ms,
|
||||||
global_data,
|
global_data,
|
||||||
global_tex
|
global_tex,
|
||||||
)
|
)
|
||||||
from libs.config import get_config
|
from scenes.dan.dan_result import DanResultScreen
|
||||||
|
from scenes.dan.dan_select import DanSelectScreen
|
||||||
|
from scenes.dan.game_dan import DanGameScreen
|
||||||
from scenes.devtest import DevScreen
|
from scenes.devtest import DevScreen
|
||||||
from scenes.entry import EntryScreen
|
from scenes.entry import EntryScreen
|
||||||
from scenes.game import GameScreen
|
from scenes.game import GameScreen
|
||||||
from scenes.dan.game_dan import DanGameScreen
|
from scenes.loading import LoadScreen
|
||||||
from scenes.practice.game import PracticeGameScreen
|
from scenes.practice.game import PracticeGameScreen
|
||||||
from scenes.practice.song_select import PracticeSongSelectScreen
|
from scenes.practice.song_select import PracticeSongSelectScreen
|
||||||
from scenes.two_player.game import TwoPlayerGameScreen
|
|
||||||
from scenes.two_player.result import TwoPlayerResultScreen
|
|
||||||
from scenes.loading import LoadScreen
|
|
||||||
from scenes.result import ResultScreen
|
from scenes.result import ResultScreen
|
||||||
from scenes.settings import SettingsScreen
|
from scenes.settings import SettingsScreen
|
||||||
from scenes.song_select import SongSelectScreen
|
from scenes.song_select import SongSelectScreen
|
||||||
from scenes.title import TitleScreen
|
from scenes.title import TitleScreen
|
||||||
|
from scenes.two_player.game import TwoPlayerGameScreen
|
||||||
|
from scenes.two_player.result import TwoPlayerResultScreen
|
||||||
from scenes.two_player.song_select import TwoPlayerSongSelectScreen
|
from scenes.two_player.song_select import TwoPlayerSongSelectScreen
|
||||||
from scenes.dan.dan_select import DanSelectScreen
|
|
||||||
from scenes.dan.dan_result import DanResultScreen
|
|
||||||
|
|
||||||
from pypresence.presence import Presence
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
DISCORD_APP_ID = '1451423960401973353'
|
DISCORD_APP_ID = '1451423960401973353'
|
||||||
|
|||||||
Submodule Skins/PyTaikoGreen updated: cc253a534d...b9dbd95dc7
@@ -29,9 +29,7 @@ rainbow = false
|
|||||||
|
|
||||||
[paths]
|
[paths]
|
||||||
tja_path = ['Songs']
|
tja_path = ['Songs']
|
||||||
video_path = ['Videos']
|
skin = 'PyTaikoGreen'
|
||||||
#You can change this path to Graphics/GreenVer1080 for the 1080p skin
|
|
||||||
graphics_path = 'Graphics/GreenVer'
|
|
||||||
|
|
||||||
[keys]
|
[keys]
|
||||||
exit_key = 'Q'
|
exit_key = 'Q'
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import cffi
|
|
||||||
import platform
|
|
||||||
import logging
|
import logging
|
||||||
|
import platform
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libs.config import VolumeConfig
|
import cffi
|
||||||
from libs.config import get_config
|
|
||||||
|
from libs.config import VolumeConfig, get_config
|
||||||
|
|
||||||
ffi = cffi.FFI()
|
ffi = cffi.FFI()
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ class AudioEngine:
|
|||||||
self.audio_device_ready = False
|
self.audio_device_ready = False
|
||||||
self.volume_presets = volume_presets
|
self.volume_presets = volume_presets
|
||||||
|
|
||||||
self.sounds_path = Path("Sounds")
|
self.sounds_path = Path(f"Skins/{get_config()["paths"]["skin"]}/Sounds")
|
||||||
|
|
||||||
def set_log_level(self, level: int):
|
def set_log_level(self, level: int):
|
||||||
lib.set_log_level(level) # type: ignore
|
lib.set_log_level(level) # type: ignore
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.bg_objects.bg_fever import BGFever4
|
from libs.bg_objects.bg_fever import BGFever4
|
||||||
from libs.bg_objects.bg_normal import BGNormal2
|
from libs.bg_objects.bg_normal import BGNormal2
|
||||||
@@ -9,6 +10,7 @@ from libs.bg_objects.renda import RendaController
|
|||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
def __init__(self, tex: TextureWrapper, player_num: PlayerNum, bpm: float, path: str, max_dancers: int):
|
def __init__(self, tex: TextureWrapper, player_num: PlayerNum, bpm: float, path: str, max_dancers: int):
|
||||||
self.tex_wrapper = tex
|
self.tex_wrapper = tex
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from libs.bg_objects.bg_fever import BGFeverBase
|
from libs.bg_objects.bg_fever import BGFeverBase
|
||||||
from libs.bg_objects.bg_normal import BGNormalBase
|
from libs.bg_objects.bg_normal import BGNormalBase
|
||||||
from libs.bg_objects.chibi import ChibiController
|
from libs.bg_objects.chibi import ChibiController
|
||||||
from libs.bg_objects.dancer import BaseDancer, BaseDancerGroup
|
from libs.bg_objects.dancer import BaseDancer, BaseDancerGroup
|
||||||
|
from libs.bg_objects.don_bg import DonBG4
|
||||||
from libs.bg_objects.fever import Fever3
|
from libs.bg_objects.fever import Fever3
|
||||||
from libs.bg_objects.footer import Footer
|
from libs.bg_objects.footer import Footer
|
||||||
from libs.bg_objects.renda import RendaController
|
from libs.bg_objects.renda import RendaController
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
from libs.bg_objects.don_bg import DonBG4
|
|
||||||
|
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from libs.bg_objects.bg_fever import BGFeverBase
|
from libs.bg_objects.bg_fever import BGFeverBase
|
||||||
from libs.bg_objects.bg_normal import BGNormalBase
|
from libs.bg_objects.bg_normal import BGNormalBase
|
||||||
from libs.bg_objects.chibi import ChibiController
|
from libs.bg_objects.chibi import ChibiController
|
||||||
from libs.bg_objects.dancer import BaseDancer, BaseDancerGroup
|
from libs.bg_objects.dancer import BaseDancer, BaseDancerGroup
|
||||||
|
from libs.bg_objects.don_bg import DonBG4
|
||||||
from libs.bg_objects.fever import Fever3
|
from libs.bg_objects.fever import Fever3
|
||||||
from libs.bg_objects.renda import RendaController
|
from libs.bg_objects.renda import RendaController
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
from libs.bg_objects.don_bg import DonBG4
|
|
||||||
|
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from libs.bg_objects.footer import Footer
|
|||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
def __init__(self, tex: TextureWrapper, player_num: PlayerNum, bpm: float, path: str, max_dancers: int):
|
def __init__(self, tex: TextureWrapper, player_num: PlayerNum, bpm: float, path: str, max_dancers: int):
|
||||||
self.tex_wrapper = tex
|
self.tex_wrapper = tex
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.bg_objects.bg_fever import BGFeverBase
|
from libs.bg_objects.bg_fever import BGFeverBase
|
||||||
from libs.bg_objects.bg_normal import BGNormalBase
|
from libs.bg_objects.bg_normal import BGNormalBase
|
||||||
from libs.bg_objects.chibi import ChibiController
|
from libs.bg_objects.chibi import ChibiController
|
||||||
from libs.bg_objects.dancer import BaseDancerGroup
|
from libs.bg_objects.dancer import BaseDancerGroup
|
||||||
|
from libs.bg_objects.don_bg import DonBGBase
|
||||||
from libs.bg_objects.fever import BaseFever
|
from libs.bg_objects.fever import BaseFever
|
||||||
from libs.bg_objects.footer import Footer
|
from libs.bg_objects.footer import Footer
|
||||||
from libs.bg_objects.renda import RendaController
|
from libs.bg_objects.renda import RendaController
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
from libs.bg_objects.don_bg import DonBGBase
|
|
||||||
|
|
||||||
import pyray as ray
|
|
||||||
|
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ from libs.bg_objects.bg_fever import BGFeverBase
|
|||||||
from libs.bg_objects.bg_normal import BGNormalBase
|
from libs.bg_objects.bg_normal import BGNormalBase
|
||||||
from libs.bg_objects.chibi import ChibiController
|
from libs.bg_objects.chibi import ChibiController
|
||||||
from libs.bg_objects.dancer import BaseDancerGroup
|
from libs.bg_objects.dancer import BaseDancerGroup
|
||||||
|
from libs.bg_objects.don_bg import DonBGBase
|
||||||
from libs.bg_objects.footer import Footer
|
from libs.bg_objects.footer import Footer
|
||||||
from libs.bg_objects.renda import RendaController
|
from libs.bg_objects.renda import RendaController
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
from libs.bg_objects.don_bg import DonBGBase
|
|
||||||
|
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.bg_objects.fever import Fever3
|
|
||||||
from libs.bg_objects.bg_fever import BGFeverBase
|
from libs.bg_objects.bg_fever import BGFeverBase
|
||||||
from libs.bg_objects.bg_normal import BGNormalBase
|
from libs.bg_objects.bg_normal import BGNormalBase
|
||||||
from libs.bg_objects.chibi import ChibiController
|
from libs.bg_objects.chibi import ChibiController
|
||||||
from libs.bg_objects.dancer import BaseDancer, BaseDancerGroup
|
from libs.bg_objects.dancer import BaseDancer, BaseDancerGroup
|
||||||
from libs.bg_objects.don_bg import DonBGBase
|
from libs.bg_objects.don_bg import DonBGBase
|
||||||
|
from libs.bg_objects.fever import Fever3
|
||||||
from libs.bg_objects.footer import Footer
|
from libs.bg_objects.footer import Footer
|
||||||
from libs.bg_objects.renda import RendaController
|
from libs.bg_objects.renda import RendaController
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
def __init__(self, tex: TextureWrapper, player_num: PlayerNum, bpm: float, path: str, max_dancers: int):
|
def __init__(self, tex: TextureWrapper, player_num: PlayerNum, bpm: float, path: str, max_dancers: int):
|
||||||
self.tex_wrapper = tex
|
self.tex_wrapper = tex
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
import pyray as ray
|
|
||||||
|
|
||||||
class Chibi:
|
class Chibi:
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import random
|
|||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
|
||||||
class Dancer:
|
class Dancer:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
|
||||||
class Fever:
|
class Fever:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
|
||||||
class Footer:
|
class Footer:
|
||||||
def __init__(self, tex: TextureWrapper, index: int, path: str = 'background'):
|
def __init__(self, tex: TextureWrapper, index: int, path: str = 'background'):
|
||||||
self.index = index
|
self.index = index
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
import pyray as ray
|
|
||||||
|
|
||||||
class Renda:
|
class Renda:
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.utils import global_tex
|
from libs.utils import global_tex
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from pathlib import Path
|
|
||||||
import tomlkit
|
|
||||||
import json
|
import json
|
||||||
|
from pathlib import Path
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
import tomlkit
|
||||||
|
|
||||||
|
|
||||||
class GeneralConfig(TypedDict):
|
class GeneralConfig(TypedDict):
|
||||||
fps_counter: bool
|
fps_counter: bool
|
||||||
@@ -30,8 +31,7 @@ class NameplateConfig(TypedDict):
|
|||||||
|
|
||||||
class PathsConfig(TypedDict):
|
class PathsConfig(TypedDict):
|
||||||
tja_path: list[Path]
|
tja_path: list[Path]
|
||||||
video_path: list[Path]
|
skin: Path
|
||||||
graphics_path: Path
|
|
||||||
|
|
||||||
class KeysConfig(TypedDict):
|
class KeysConfig(TypedDict):
|
||||||
exit_key: int
|
exit_key: int
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
from enum import IntEnum
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
|
||||||
import random
|
import random
|
||||||
|
import sqlite3
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from enum import IntEnum
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from raylib import SHADER_UNIFORM_VEC3
|
|
||||||
from libs.audio import audio
|
|
||||||
from libs.animation import Animation, MoveAnimation
|
|
||||||
from libs.global_data import Crown, Difficulty, ScoreMethod
|
|
||||||
from libs.tja import TJAParser, test_encodings
|
|
||||||
from libs.texture import tex
|
|
||||||
from libs.utils import OutlinedText, get_current_ms, global_data
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import sqlite3
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
from raylib import SHADER_UNIFORM_VEC3
|
||||||
|
|
||||||
|
from libs.animation import Animation, MoveAnimation
|
||||||
|
from libs.audio import audio
|
||||||
|
from libs.global_data import Crown, Difficulty, ScoreMethod
|
||||||
|
from libs.texture import tex
|
||||||
|
from libs.tja import TJAParser, test_encodings
|
||||||
|
from libs.utils import OutlinedText, get_current_ms, global_data
|
||||||
|
|
||||||
BOX_CENTER = 594 * tex.screen_scale
|
BOX_CENTER = 594 * tex.screen_scale
|
||||||
|
|
||||||
@@ -109,18 +110,22 @@ class BaseBox():
|
|||||||
else:
|
else:
|
||||||
self.fore_color = ray.Color(101, 0, 82, 255)
|
self.fore_color = ray.Color(101, 0, 82, 255)
|
||||||
self.position = float('inf')
|
self.position = float('inf')
|
||||||
self.start_position = -1.0
|
self.start_position = float('inf')
|
||||||
self.target_position = -1.0
|
self.target_position = float('inf')
|
||||||
self.open_anim = Animation.create_move(233, total_distance=150*tex.screen_scale, delay=50)
|
self.open_anim = Animation.create_move(233, total_distance=150*tex.screen_scale, delay=50)
|
||||||
self.open_fade = Animation.create_fade(200, initial_opacity=0, final_opacity=1.0)
|
self.open_fade = Animation.create_fade(200, initial_opacity=0, final_opacity=1.0)
|
||||||
self.move = None
|
self.move = Animation.create_move(133, total_distance=100 * tex.screen_scale, ease_out='cubic')
|
||||||
|
self.move.start()
|
||||||
self.shader = None
|
self.shader = None
|
||||||
self.is_open = False
|
self.is_open = False
|
||||||
self.text_loaded = False
|
self.text_loaded = False
|
||||||
self.wait = 0
|
self.wait = 0
|
||||||
|
|
||||||
def load_text(self):
|
def load_text(self):
|
||||||
self.name = OutlinedText(self.text_name, tex.skin_config["song_box_name"].font_size, ray.WHITE, outline_thickness=5, vertical=True)
|
font_size = tex.skin_config["song_box_name"].font_size
|
||||||
|
if len(self.text_name) >= 30:
|
||||||
|
font_size -= int(10 * tex.screen_scale)
|
||||||
|
self.name = OutlinedText(self.text_name, font_size, ray.WHITE, outline_thickness=5, vertical=True)
|
||||||
if self.back_color is not None:
|
if self.back_color is not None:
|
||||||
self.shader = ray.load_shader('shader/dummy.vs', 'shader/colortransform.fs')
|
self.shader = ray.load_shader('shader/dummy.vs', 'shader/colortransform.fs')
|
||||||
source_rgb = (142, 212, 30)
|
source_rgb = (142, 212, 30)
|
||||||
@@ -132,30 +137,22 @@ class BaseBox():
|
|||||||
ray.set_shader_value(self.shader, source_loc, source_color, SHADER_UNIFORM_VEC3)
|
ray.set_shader_value(self.shader, source_loc, source_color, SHADER_UNIFORM_VEC3)
|
||||||
ray.set_shader_value(self.shader, target_loc, target_color, SHADER_UNIFORM_VEC3)
|
ray.set_shader_value(self.shader, target_loc, target_color, SHADER_UNIFORM_VEC3)
|
||||||
|
|
||||||
def move_box(self, current_time: float):
|
def move_box(self, direction: int):
|
||||||
if self.position != self.target_position and self.move is None:
|
if self.position != self.target_position:
|
||||||
if self.position < self.target_position:
|
distance = abs(self.target_position - self.position)
|
||||||
direction = 1
|
self.move = Animation.create_move(133, total_distance=distance * tex.screen_scale * direction, ease_out='cubic')
|
||||||
else:
|
|
||||||
direction = -1
|
|
||||||
if abs(self.target_position - self.position) > 250 * tex.screen_scale:
|
|
||||||
direction *= -1
|
|
||||||
self.move = Animation.create_move(133, total_distance=100 * direction * tex.screen_scale, ease_out='cubic')
|
|
||||||
self.move.start()
|
|
||||||
if self.is_open or self.target_position == BOX_CENTER:
|
|
||||||
self.move.total_distance = int(250 * direction * tex.screen_scale)
|
|
||||||
self.start_position = self.position
|
self.start_position = self.position
|
||||||
if self.move is not None:
|
self.move.start()
|
||||||
self.move.update(current_time)
|
|
||||||
self.position = self.start_position + int(self.move.attribute)
|
|
||||||
if self.move.is_finished:
|
|
||||||
self.position = self.target_position
|
|
||||||
self.move = None
|
|
||||||
|
|
||||||
def update(self, current_time: float, is_diff_select: bool):
|
def update(self, current_time: float, is_diff_select: bool):
|
||||||
self.is_diff_select = is_diff_select
|
self.is_diff_select = is_diff_select
|
||||||
self.open_anim.update(current_time)
|
self.open_anim.update(current_time)
|
||||||
self.open_fade.update(current_time)
|
self.open_fade.update(current_time)
|
||||||
|
self.move.update(current_time)
|
||||||
|
if not self.move.is_finished:
|
||||||
|
self.position = self.start_position + int(self.move.attribute)
|
||||||
|
else:
|
||||||
|
self.position = self.target_position
|
||||||
|
|
||||||
def _draw_closed(self, x: float, y: float, outer_fade_override: float):
|
def _draw_closed(self, x: float, y: float, outer_fade_override: float):
|
||||||
if self.shader is not None and self.texture_index == TextureIndex.BLANK:
|
if self.shader is not None and self.texture_index == TextureIndex.BLANK:
|
||||||
@@ -192,7 +189,6 @@ class BackBox(BaseBox):
|
|||||||
def update(self, current_time: float, is_diff_select: bool):
|
def update(self, current_time: float, is_diff_select: bool):
|
||||||
super().update(current_time, is_diff_select)
|
super().update(current_time, is_diff_select)
|
||||||
is_open_prev = self.is_open
|
is_open_prev = self.is_open
|
||||||
self.move_box(current_time)
|
|
||||||
self.is_open = self.position == BOX_CENTER
|
self.is_open = self.position == BOX_CENTER
|
||||||
|
|
||||||
if self.yellow_box is not None:
|
if self.yellow_box is not None:
|
||||||
@@ -253,7 +249,6 @@ class SongBox(BaseBox):
|
|||||||
def update(self, current_time: float, is_diff_select: bool):
|
def update(self, current_time: float, is_diff_select: bool):
|
||||||
super().update(current_time, is_diff_select)
|
super().update(current_time, is_diff_select)
|
||||||
is_open_prev = self.is_open
|
is_open_prev = self.is_open
|
||||||
self.move_box(current_time)
|
|
||||||
self.is_open = self.position == BOX_CENTER
|
self.is_open = self.position == BOX_CENTER
|
||||||
|
|
||||||
if self.yellow_box is not None:
|
if self.yellow_box is not None:
|
||||||
@@ -324,7 +319,6 @@ class FolderBox(BaseBox):
|
|||||||
def update(self, current_time: float, is_diff_select: bool):
|
def update(self, current_time: float, is_diff_select: bool):
|
||||||
super().update(current_time, is_diff_select)
|
super().update(current_time, is_diff_select)
|
||||||
is_open_prev = self.is_open
|
is_open_prev = self.is_open
|
||||||
self.move_box(current_time)
|
|
||||||
self.is_open = self.position == BOX_CENTER
|
self.is_open = self.position == BOX_CENTER
|
||||||
|
|
||||||
if not is_open_prev and self.is_open:
|
if not is_open_prev and self.is_open:
|
||||||
@@ -652,7 +646,6 @@ class DanBox(BaseBox):
|
|||||||
def update(self, current_time: float, is_diff_select: bool):
|
def update(self, current_time: float, is_diff_select: bool):
|
||||||
super().update(current_time, is_diff_select)
|
super().update(current_time, is_diff_select)
|
||||||
is_open_prev = self.is_open
|
is_open_prev = self.is_open
|
||||||
self.move_box(current_time)
|
|
||||||
self.is_open = self.position == BOX_CENTER
|
self.is_open = self.position == BOX_CENTER
|
||||||
if not is_open_prev and self.is_open:
|
if not is_open_prev and self.is_open:
|
||||||
self.yellow_box = YellowBox(False, is_dan=True)
|
self.yellow_box = YellowBox(False, is_dan=True)
|
||||||
@@ -781,7 +774,8 @@ class GenreBG:
|
|||||||
if self.shader is not None and self.end_box.texture_index == TextureIndex.BLANK:
|
if self.shader is not None and self.end_box.texture_index == TextureIndex.BLANK:
|
||||||
ray.begin_shader_mode(self.shader)
|
ray.begin_shader_mode(self.shader)
|
||||||
offset = (tex.skin_config["genre_bg_offset"].x * -1) if self.start_box.is_open else 0
|
offset = (tex.skin_config["genre_bg_offset"].x * -1) if self.start_box.is_open else 0
|
||||||
|
if (344 * tex.screen_scale < self.start_box.position < 594 * tex.screen_scale):
|
||||||
|
offset = -self.start_position + 444 * tex.screen_scale
|
||||||
tex.draw_texture('box', 'folder_background_edge', frame=self.end_box.texture_index, x=self.start_position+offset, y=y, mirror="horizontal", fade=self.fade_in.attribute)
|
tex.draw_texture('box', 'folder_background_edge', frame=self.end_box.texture_index, x=self.start_position+offset, y=y, mirror="horizontal", fade=self.fade_in.attribute)
|
||||||
|
|
||||||
|
|
||||||
@@ -803,6 +797,8 @@ class GenreBG:
|
|||||||
tex.draw_texture('box', 'folder_background', x=tex.skin_config["genre_bg_folder_background"].x, y=y, x2=x2, frame=self.end_box.texture_index)
|
tex.draw_texture('box', 'folder_background', x=tex.skin_config["genre_bg_folder_background"].x, y=y, x2=x2, frame=self.end_box.texture_index)
|
||||||
|
|
||||||
|
|
||||||
|
if (594 * tex.screen_scale < self.end_box.position < 844 * tex.screen_scale):
|
||||||
|
offset = -self.end_position + 674 * tex.screen_scale
|
||||||
offset = tex.skin_config["genre_bg_offset"].x if self.end_box.is_open else 0
|
offset = tex.skin_config["genre_bg_offset"].x if self.end_box.is_open else 0
|
||||||
tex.draw_texture('box', 'folder_background_edge', x=self.end_position+tex.skin_config["genre_bg_folder_edge"].x+offset, y=y, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
|
tex.draw_texture('box', 'folder_background_edge', x=self.end_position+tex.skin_config["genre_bg_folder_edge"].x+offset, y=y, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
|
||||||
|
|
||||||
@@ -861,13 +857,11 @@ class ScoreHistory:
|
|||||||
tex.draw_texture('leaderboard', 'shinuchi_ura', index=self.long)
|
tex.draw_texture('leaderboard', 'shinuchi_ura', index=self.long)
|
||||||
else:
|
else:
|
||||||
tex.draw_texture('leaderboard', 'shinuchi', index=self.long)
|
tex.draw_texture('leaderboard', 'shinuchi', index=self.long)
|
||||||
|
tex.draw_texture('leaderboard', 'pts', color=ray.WHITE, index=self.long)
|
||||||
case ScoreMethod.GEN3:
|
case ScoreMethod.GEN3:
|
||||||
if self.curr_difficulty == Difficulty.URA:
|
|
||||||
tex.draw_texture('leaderboard', 'normal', index=self.long)
|
|
||||||
else:
|
|
||||||
tex.draw_texture('leaderboard', 'normal', index=self.long)
|
tex.draw_texture('leaderboard', 'normal', index=self.long)
|
||||||
|
tex.draw_texture('leaderboard', 'pts', color=ray.BLACK, index=self.long)
|
||||||
|
|
||||||
tex.draw_texture('leaderboard', 'pts', color=ray.WHITE, index=self.long)
|
|
||||||
tex.draw_texture('leaderboard', 'difficulty', frame=self.curr_difficulty, index=self.long)
|
tex.draw_texture('leaderboard', 'difficulty', frame=self.curr_difficulty, index=self.long)
|
||||||
|
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
@@ -887,7 +881,11 @@ class ScoreHistory:
|
|||||||
margin = tex.skin_config["score_info_counter_margin"].x
|
margin = tex.skin_config["score_info_counter_margin"].x
|
||||||
for i in range(len(counter)):
|
for i in range(len(counter)):
|
||||||
if j == 0:
|
if j == 0:
|
||||||
tex.draw_texture('leaderboard', 'counter', frame=int(counter[i]), x=-((len(counter) * tex.skin_config["score_info_counter_margin"].width) // 2) + (i * tex.skin_config["score_info_counter_margin"].width), color=ray.WHITE, index=self.long)
|
match global_data.config["general"]["score_method"]:
|
||||||
|
case ScoreMethod.SHINUCHI:
|
||||||
|
tex.draw_texture('leaderboard', 'counter', frame=int(counter[i]), x=-((len(counter) * tex.skin_config["score_info_counter_margin"].width) // 2) + (i * tex.skin_config["score_info_counter_margin"].width), color=ray.WHITE, index=self.long)
|
||||||
|
case ScoreMethod.GEN3:
|
||||||
|
tex.draw_texture('leaderboard', 'counter', frame=int(counter[i]), x=-((len(counter) * tex.skin_config["score_info_counter_margin"].width) // 2) + (i * tex.skin_config["score_info_counter_margin"].width), color=ray.BLACK, index=self.long)
|
||||||
else:
|
else:
|
||||||
tex.draw_texture('leaderboard', 'judge_num', frame=int(counter[i]), x=-(len(counter) - i) * margin, y=j*tex.skin_config["score_info_bg_offset"].y)
|
tex.draw_texture('leaderboard', 'judge_num', frame=int(counter[i]), x=-(len(counter) - i) * margin, y=j*tex.skin_config["score_info_bg_offset"].y)
|
||||||
|
|
||||||
@@ -1346,6 +1344,54 @@ class FileNavigator:
|
|||||||
"""Check if currently at the virtual root"""
|
"""Check if currently at the virtual root"""
|
||||||
return self.current_dir == Path()
|
return self.current_dir == Path()
|
||||||
|
|
||||||
|
def load_new_items(self, selected_item, dir_key: str):
|
||||||
|
return self.new_items
|
||||||
|
|
||||||
|
def load_recent_items(self, selected_item, dir_key: str):
|
||||||
|
if self.recent_folder is None:
|
||||||
|
raise Exception("tried to enter recent folder without recents")
|
||||||
|
self._generate_objects_recursive(self.recent_folder.path)
|
||||||
|
if not isinstance(selected_item.box, BackBox):
|
||||||
|
selected_item.box.tja_count = self._count_tja_files(self.recent_folder.path)
|
||||||
|
return self.directory_contents[dir_key]
|
||||||
|
|
||||||
|
def load_favorite_items(self, selected_item, dir_key: str):
|
||||||
|
if self.favorite_folder is None:
|
||||||
|
raise Exception("tried to enter favorite folder without favorites")
|
||||||
|
self._generate_objects_recursive(self.favorite_folder.path)
|
||||||
|
tja_files = self._get_tja_files_for_directory(self.favorite_folder.path)
|
||||||
|
self._calculate_directory_crowns(dir_key, tja_files)
|
||||||
|
if not isinstance(selected_item.box, BackBox):
|
||||||
|
selected_item.box.tja_count = self._count_tja_files(self.favorite_folder.path)
|
||||||
|
self.in_favorites = True
|
||||||
|
return self.directory_contents[dir_key]
|
||||||
|
|
||||||
|
def load_diff_sort_items(self, selected_item, dir_key: str):
|
||||||
|
content_items = []
|
||||||
|
parent_dir = selected_item.path.parent
|
||||||
|
for sibling_path in parent_dir.iterdir():
|
||||||
|
if sibling_path.is_dir() and sibling_path != selected_item.path:
|
||||||
|
sibling_key = str(sibling_path)
|
||||||
|
if sibling_key in self.directory_contents:
|
||||||
|
for item in self.directory_contents[sibling_key]:
|
||||||
|
if isinstance(item, SongFile) and item:
|
||||||
|
if self.diff_sort_diff in item.tja.metadata.course_data and item.tja.metadata.course_data[self.diff_sort_diff].level == self.diff_sort_level:
|
||||||
|
if item not in content_items:
|
||||||
|
content_items.append(item)
|
||||||
|
return content_items
|
||||||
|
|
||||||
|
def load_recommended_items(self, selected_item, dir_key: str):
|
||||||
|
parent_dir = selected_item.path.parent
|
||||||
|
temp_items = []
|
||||||
|
for sibling_path in parent_dir.iterdir():
|
||||||
|
if sibling_path.is_dir() and sibling_path != selected_item.path:
|
||||||
|
sibling_key = str(sibling_path)
|
||||||
|
if sibling_key in self.directory_contents:
|
||||||
|
for item in self.directory_contents[sibling_key]:
|
||||||
|
if not isinstance(item, Directory) and isinstance(item, SongFile):
|
||||||
|
temp_items.append(item)
|
||||||
|
return random.sample(temp_items, min(10, len(temp_items)))
|
||||||
|
|
||||||
def load_current_directory(self, selected_item: Optional[Directory] = None):
|
def load_current_directory(self, selected_item: Optional[Directory] = None):
|
||||||
"""Load pre-generated items for the current directory (unified for root and subdirs)"""
|
"""Load pre-generated items for the current directory (unified for root and subdirs)"""
|
||||||
dir_key = str(self.current_dir)
|
dir_key = str(self.current_dir)
|
||||||
@@ -1383,47 +1429,15 @@ class FileNavigator:
|
|||||||
# Handle special collections (same logic as before)
|
# Handle special collections (same logic as before)
|
||||||
if isinstance(selected_item, Directory):
|
if isinstance(selected_item, Directory):
|
||||||
if selected_item.collection == Directory.COLLECTIONS[0]:
|
if selected_item.collection == Directory.COLLECTIONS[0]:
|
||||||
content_items = self.new_items
|
content_items = self.load_new_items(selected_item, dir_key)
|
||||||
elif selected_item.collection == Directory.COLLECTIONS[1]:
|
elif selected_item.collection == Directory.COLLECTIONS[1]:
|
||||||
if self.recent_folder is None:
|
content_items = self.load_recent_items(selected_item, dir_key)
|
||||||
raise Exception("tried to enter recent folder without recents")
|
|
||||||
self._generate_objects_recursive(self.recent_folder.path)
|
|
||||||
if not isinstance(selected_item.box, BackBox):
|
|
||||||
selected_item.box.tja_count = self._count_tja_files(self.recent_folder.path)
|
|
||||||
content_items = self.directory_contents[dir_key]
|
|
||||||
elif selected_item.collection == Directory.COLLECTIONS[2]:
|
elif selected_item.collection == Directory.COLLECTIONS[2]:
|
||||||
if self.favorite_folder is None:
|
content_items = self.load_favorite_items(selected_item, dir_key)
|
||||||
raise Exception("tried to enter favorite folder without favorites")
|
|
||||||
self._generate_objects_recursive(self.favorite_folder.path)
|
|
||||||
tja_files = self._get_tja_files_for_directory(self.favorite_folder.path)
|
|
||||||
self._calculate_directory_crowns(dir_key, tja_files)
|
|
||||||
if not isinstance(selected_item.box, BackBox):
|
|
||||||
selected_item.box.tja_count = self._count_tja_files(self.favorite_folder.path)
|
|
||||||
content_items = self.directory_contents[dir_key]
|
|
||||||
self.in_favorites = True
|
|
||||||
elif selected_item.collection == Directory.COLLECTIONS[3]:
|
elif selected_item.collection == Directory.COLLECTIONS[3]:
|
||||||
content_items = []
|
content_items = self.load_diff_sort_items(selected_item, dir_key)
|
||||||
parent_dir = selected_item.path.parent
|
|
||||||
for sibling_path in parent_dir.iterdir():
|
|
||||||
if sibling_path.is_dir() and sibling_path != selected_item.path:
|
|
||||||
sibling_key = str(sibling_path)
|
|
||||||
if sibling_key in self.directory_contents:
|
|
||||||
for item in self.directory_contents[sibling_key]:
|
|
||||||
if isinstance(item, SongFile) and item:
|
|
||||||
if self.diff_sort_diff in item.tja.metadata.course_data and item.tja.metadata.course_data[self.diff_sort_diff].level == self.diff_sort_level:
|
|
||||||
if item not in content_items:
|
|
||||||
content_items.append(item)
|
|
||||||
elif selected_item.collection == Directory.COLLECTIONS[4]:
|
elif selected_item.collection == Directory.COLLECTIONS[4]:
|
||||||
parent_dir = selected_item.path.parent
|
content_items = self.load_recommended_items(selected_item, dir_key)
|
||||||
temp_items = []
|
|
||||||
for sibling_path in parent_dir.iterdir():
|
|
||||||
if sibling_path.is_dir() and sibling_path != selected_item.path:
|
|
||||||
sibling_key = str(sibling_path)
|
|
||||||
if sibling_key in self.directory_contents:
|
|
||||||
for item in self.directory_contents[sibling_key]:
|
|
||||||
if not isinstance(item, Directory) and isinstance(item, SongFile):
|
|
||||||
temp_items.append(item)
|
|
||||||
content_items = random.sample(temp_items, min(10, len(temp_items)))
|
|
||||||
|
|
||||||
if content_items == []:
|
if content_items == []:
|
||||||
self.go_back()
|
self.go_back()
|
||||||
@@ -1494,7 +1508,7 @@ class FileNavigator:
|
|||||||
# Save current state to history
|
# Save current state to history
|
||||||
self.history.append((self.current_dir, self.selected_index))
|
self.history.append((self.current_dir, self.selected_index))
|
||||||
self.current_dir = selected_item.path
|
self.current_dir = selected_item.path
|
||||||
logger.info(f"Entered Directory {selected_item.path}")
|
logger.info(f"Entered Directory {selected_item.path} at index {self.selected_index}")
|
||||||
|
|
||||||
self.load_current_directory(selected_item=selected_item)
|
self.load_current_directory(selected_item=selected_item)
|
||||||
|
|
||||||
@@ -1744,19 +1758,19 @@ class FileNavigator:
|
|||||||
def navigate_left(self):
|
def navigate_left(self):
|
||||||
"""Move selection left with wrap-around"""
|
"""Move selection left with wrap-around"""
|
||||||
if self.items:
|
if self.items:
|
||||||
if self.items[0].box.move is not None and not self.items[0].box.move.is_finished:
|
|
||||||
return
|
|
||||||
self.selected_index = (self.selected_index - 1) % len(self.items)
|
self.selected_index = (self.selected_index - 1) % len(self.items)
|
||||||
self.calculate_box_positions()
|
self.calculate_box_positions()
|
||||||
|
for item in self.items:
|
||||||
|
item.box.move_box(1)
|
||||||
logger.info(f"Moved Left to {self.items[self.selected_index].path}")
|
logger.info(f"Moved Left to {self.items[self.selected_index].path}")
|
||||||
|
|
||||||
def navigate_right(self):
|
def navigate_right(self):
|
||||||
"""Move selection right with wrap-around"""
|
"""Move selection right with wrap-around"""
|
||||||
if self.items:
|
if self.items:
|
||||||
if self.items[0].box.move is not None and not self.items[0].box.move.is_finished:
|
|
||||||
return
|
|
||||||
self.selected_index = (self.selected_index + 1) % len(self.items)
|
self.selected_index = (self.selected_index + 1) % len(self.items)
|
||||||
self.calculate_box_positions()
|
self.calculate_box_positions()
|
||||||
|
for item in self.items:
|
||||||
|
item.box.move_box(-1)
|
||||||
logger.info(f"Moved Right to {self.items[self.selected_index].path}")
|
logger.info(f"Moved Right to {self.items[self.selected_index].path}")
|
||||||
|
|
||||||
def skip_left(self):
|
def skip_left(self):
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import pyray as ray
|
|||||||
|
|
||||||
from libs.config import Config
|
from libs.config import Config
|
||||||
|
|
||||||
|
|
||||||
class PlayerNum(IntEnum):
|
class PlayerNum(IntEnum):
|
||||||
ALL = 0
|
ALL = 0
|
||||||
P1 = 1
|
P1 = 1
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.global_data import PlayerNum
|
|
||||||
from libs.utils import OutlinedText, global_tex
|
|
||||||
from libs.config import get_config
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
|
from libs.config import get_config
|
||||||
|
from libs.global_data import PlayerNum, global_data
|
||||||
|
from libs.utils import OutlinedText, global_tex
|
||||||
|
|
||||||
|
|
||||||
class Nameplate:
|
class Nameplate:
|
||||||
@@ -98,6 +99,7 @@ class Indicator:
|
|||||||
self.don_fade = global_tex.get_animation(6)
|
self.don_fade = global_tex.get_animation(6)
|
||||||
self.blue_arrow_move = global_tex.get_animation(7)
|
self.blue_arrow_move = global_tex.get_animation(7)
|
||||||
self.blue_arrow_fade = global_tex.get_animation(8)
|
self.blue_arrow_fade = global_tex.get_animation(8)
|
||||||
|
self.select_text = OutlinedText(global_tex.skin_config["indicator_text"].text[global_data.config["general"]["language"]], global_tex.skin_config["indicator_text"].font_size, ray.WHITE, spacing=-3)
|
||||||
|
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
"""Update the indicator's animations."""
|
"""Update the indicator's animations."""
|
||||||
@@ -109,7 +111,8 @@ class Indicator:
|
|||||||
"""Draw the indicator at the given position with the given fade."""
|
"""Draw the indicator at the given position with the given fade."""
|
||||||
tex = global_tex
|
tex = global_tex
|
||||||
tex.draw_texture('indicator', 'background', x=x, y=y, fade=fade)
|
tex.draw_texture('indicator', 'background', x=x, y=y, fade=fade)
|
||||||
tex.draw_texture('indicator', 'text', frame=self.state.value, x=x, y=y, fade=fade)
|
tex.draw_texture('indicator', 'text', frame=self.state.value, x=x, y=y, fade=fade, color=ray.BLACK)
|
||||||
|
self.select_text.draw(ray.BLANK, x=x+global_tex.skin_config["indicator_text"].x, y=y, fade=fade)
|
||||||
tex.draw_texture('indicator', 'drum_face', index=self.state.value, x=x, y=y, fade=fade)
|
tex.draw_texture('indicator', 'drum_face', index=self.state.value, x=x, y=y, fade=fade)
|
||||||
if self.state == Indicator.State.SELECT:
|
if self.state == Indicator.State.SELECT:
|
||||||
tex.draw_texture('indicator', 'drum_kat', fade=min(fade, self.don_fade.attribute), x=x, y=y)
|
tex.draw_texture('indicator', 'drum_kat', fade=min(fade, self.don_fade.attribute), x=x, y=y)
|
||||||
@@ -127,15 +130,14 @@ class CoinOverlay:
|
|||||||
"""Coin overlay for the game."""
|
"""Coin overlay for the game."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize the coin overlay."""
|
"""Initialize the coin overlay."""
|
||||||
pass
|
self.free_play = OutlinedText(global_tex.skin_config["free_play"].text[global_data.config["general"]["language"]], global_tex.skin_config["free_play"].font_size, ray.WHITE, spacing=5, outline_thickness=4)
|
||||||
def update(self, current_time_ms: float):
|
def update(self, current_time_ms: float):
|
||||||
"""Update the coin overlay. Unimplemented"""
|
"""Update the coin overlay. Unimplemented"""
|
||||||
pass
|
pass
|
||||||
def draw(self, x: int = 0, y: int = 0):
|
def draw(self, x: int = 0, y: int = 0):
|
||||||
"""Draw the coin overlay.
|
"""Draw the coin overlay.
|
||||||
Only draws free play for now."""
|
Only draws free play for now."""
|
||||||
tex = global_tex
|
self.free_play.draw(ray.BLACK, x=global_tex.screen_width//2 - self.free_play.texture.width//2, y=global_tex.skin_config["free_play"].y)
|
||||||
tex.draw_texture('overlay', 'free_play', x=x, y=y)
|
|
||||||
|
|
||||||
class AllNetIcon:
|
class AllNetIcon:
|
||||||
"""All.Net status icon for the game."""
|
"""All.Net status icon for the game."""
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import configparser
|
import configparser
|
||||||
import logging
|
import csv
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import time
|
import time
|
||||||
import csv
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from libs.config import get_config
|
||||||
from libs.global_data import Crown
|
from libs.global_data import Crown
|
||||||
from libs.tja import NoteList, TJAParser, test_encodings
|
from libs.tja import NoteList, TJAParser, test_encodings
|
||||||
from libs.utils import global_data
|
from libs.utils import global_data
|
||||||
from libs.config import get_config
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
DB_VERSION = 1
|
DB_VERSION = 1
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import raylib as ray
|
import raylib as ray
|
||||||
from pyray import Vector2, Rectangle, Color
|
from pyray import Color, Rectangle, Vector2
|
||||||
|
|
||||||
from libs.animation import BaseAnimation, parse_animations
|
from libs.animation import BaseAnimation, parse_animations
|
||||||
|
|
||||||
from libs.config import get_config
|
from libs.config import get_config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SkinInfo:
|
class SkinInfo:
|
||||||
def __init__(self, x: float, y: float, font_size: int, width: float, height: float):
|
def __init__(self, x: float, y: float, font_size: int, width: float, height: float, text: dict[str, str]):
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
self.font_size = font_size
|
self.font_size = font_size
|
||||||
|
self.text = text
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.__dict__}"
|
return f"{self.__dict__}"
|
||||||
@@ -73,24 +71,24 @@ class TextureWrapper:
|
|||||||
self.textures: dict[str, dict[str, Texture | FramedTexture]] = dict()
|
self.textures: dict[str, dict[str, Texture | FramedTexture]] = dict()
|
||||||
self.animations: dict[int, BaseAnimation] = dict()
|
self.animations: dict[int, BaseAnimation] = dict()
|
||||||
self.skin_config: dict[str, SkinInfo] = dict()
|
self.skin_config: dict[str, SkinInfo] = dict()
|
||||||
self.graphics_path = Path(get_config()['paths']['graphics_path'])
|
self.graphics_path = Path(f'Skins/{get_config()['paths']['skin']}/Graphics')
|
||||||
self.parent_graphics_path = Path(get_config()['paths']['graphics_path'])
|
self.parent_graphics_path = Path(f'Skins/{get_config()['paths']['skin']}/Graphics')
|
||||||
if not (self.graphics_path / "skin_config.json").exists():
|
if not (self.graphics_path / "skin_config.json").exists():
|
||||||
raise Exception("skin is missing a skin_config.json")
|
raise Exception("skin is missing a skin_config.json")
|
||||||
|
|
||||||
data = json.loads((self.graphics_path / "skin_config.json").read_text())
|
data = json.loads((self.graphics_path / "skin_config.json").read_text(encoding='utf-8'))
|
||||||
self.skin_config: dict[str, SkinInfo] = {
|
self.skin_config: dict[str, SkinInfo] = {
|
||||||
k: SkinInfo(v.get('x', 0), v.get('y', 0), v.get('font_size', 0), v.get('width', 0), v.get('height', 0)) for k, v in data.items()
|
k: SkinInfo(v.get('x', 0), v.get('y', 0), v.get('font_size', 0), v.get('width', 0), v.get('height', 0), v.get('text', dict())) for k, v in data.items()
|
||||||
}
|
}
|
||||||
self.screen_width = int(self.skin_config["screen"].width)
|
self.screen_width = int(self.skin_config["screen"].width)
|
||||||
self.screen_height = int(self.skin_config["screen"].height)
|
self.screen_height = int(self.skin_config["screen"].height)
|
||||||
self.screen_scale = self.screen_width / 1280
|
self.screen_scale = self.screen_width / 1280
|
||||||
if "parent" in data["screen"]:
|
if "parent" in data["screen"]:
|
||||||
parent = data["screen"]["parent"]
|
parent = data["screen"]["parent"]
|
||||||
self.parent_graphics_path = Path("Graphics") / parent
|
self.parent_graphics_path = Path("Skins") / parent
|
||||||
parent_data = json.loads((self.parent_graphics_path / "skin_config.json").read_text())
|
parent_data = json.loads((self.parent_graphics_path / "skin_config.json").read_text(encoding='utf-8'))
|
||||||
for k, v in parent_data.items():
|
for k, v in parent_data.items():
|
||||||
self.skin_config[k] = SkinInfo(v.get('x', 0) * self.screen_scale, v.get('y', 0) * self.screen_scale, v.get('font_size', 0) * self.screen_scale, v.get('width', 0) * self.screen_scale, v.get('height', 0) * self.screen_scale)
|
self.skin_config[k] = SkinInfo(v.get('x', 0) * self.screen_scale, v.get('y', 0) * self.screen_scale, v.get('font_size', 0) * self.screen_scale, v.get('width', 0) * self.screen_scale, v.get('height', 0) * self.screen_scale, v.get('text', dict()))
|
||||||
|
|
||||||
def unload_textures(self):
|
def unload_textures(self):
|
||||||
"""Unload all textures and animations."""
|
"""Unload all textures and animations."""
|
||||||
@@ -189,7 +187,7 @@ class TextureWrapper:
|
|||||||
if screen_name in self.textures and subset in self.textures[screen_name]:
|
if screen_name in self.textures and subset in self.textures[screen_name]:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
if not os.path.isfile(folder / 'texture.json'):
|
if not (folder / 'texture.json').exists():
|
||||||
raise Exception(f"texture.json file missing from {folder}")
|
raise Exception(f"texture.json file missing from {folder}")
|
||||||
|
|
||||||
with open(folder / 'texture.json') as json_file:
|
with open(folder / 'texture.json') as json_file:
|
||||||
@@ -205,7 +203,7 @@ class TextureWrapper:
|
|||||||
if tex_dir.is_dir():
|
if tex_dir.is_dir():
|
||||||
frames = [ray.LoadTexture(str(frame).encode(encoding)) for frame in sorted(tex_dir.iterdir(),
|
frames = [ray.LoadTexture(str(frame).encode(encoding)) for frame in sorted(tex_dir.iterdir(),
|
||||||
key=lambda x: int(x.stem)) if frame.is_file()]
|
key=lambda x: int(x.stem)) if frame.is_file()]
|
||||||
self.textures[folder.stem][tex_name] = Texture(tex_name, frames, tex_mapping)
|
self.textures[folder.stem][tex_name] = FramedTexture(tex_name, frames, tex_mapping)
|
||||||
self._read_tex_obj_data(tex_mapping, self.textures[folder.stem][tex_name])
|
self._read_tex_obj_data(tex_mapping, self.textures[folder.stem][tex_name])
|
||||||
elif tex_file.is_file():
|
elif tex_file.is_file():
|
||||||
tex = ray.LoadTexture(str(tex_file).encode(encoding))
|
tex = ray.LoadTexture(str(tex_file).encode(encoding))
|
||||||
@@ -230,7 +228,7 @@ class TextureWrapper:
|
|||||||
|
|
||||||
# Load zip files from child screen path only
|
# Load zip files from child screen path only
|
||||||
for zip_file in screen_path.iterdir():
|
for zip_file in screen_path.iterdir():
|
||||||
if zip_file.is_file() and zip_file.suffix == ".zip":
|
if zip_file.is_dir():
|
||||||
self.load_zip(screen_name, zip_file.stem)
|
self.load_zip(screen_name, zip_file.stem)
|
||||||
|
|
||||||
logger.info(f"Screen textures loaded for: {screen_name}")
|
logger.info(f"Screen textures loaded for: {screen_name}")
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from enum import IntEnum
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import math
|
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from dataclasses import dataclass, field, fields
|
from dataclasses import dataclass, field, fields
|
||||||
|
from enum import IntEnum
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import string
|
||||||
import ctypes
|
import ctypes
|
||||||
import hashlib
|
import hashlib
|
||||||
import sys
|
import sys
|
||||||
@@ -135,7 +136,7 @@ for file in Path('cache/image').iterdir():
|
|||||||
|
|
||||||
class OutlinedText:
|
class OutlinedText:
|
||||||
"""Create an outlined text object."""
|
"""Create an outlined text object."""
|
||||||
def __init__(self, text: str, font_size: int, color: ray.Color, outline_thickness=5.0, vertical=False):
|
def __init__(self, text: str, font_size: int, color: ray.Color, outline_thickness=5.0, vertical=False, spacing=1):
|
||||||
"""
|
"""
|
||||||
Create an outlined text object.
|
Create an outlined text object.
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ class OutlinedText:
|
|||||||
if vertical:
|
if vertical:
|
||||||
self.texture = self._create_text_vertical(text, font_size, color, ray.BLANK, self.font)
|
self.texture = self._create_text_vertical(text, font_size, color, ray.BLANK, self.font)
|
||||||
else:
|
else:
|
||||||
self.texture = self._create_text_horizontal(text, font_size, color, ray.BLANK, self.font)
|
self.texture = self._create_text_horizontal(text, font_size, color, ray.BLANK, self.font, spacing=spacing)
|
||||||
ray.gen_texture_mipmaps(self.texture)
|
ray.gen_texture_mipmaps(self.texture)
|
||||||
ray.set_texture_filter(self.texture, ray.TextureFilter.TEXTURE_FILTER_TRILINEAR)
|
ray.set_texture_filter(self.texture, ray.TextureFilter.TEXTURE_FILTER_TRILINEAR)
|
||||||
outline_size = ray.ffi.new('float*', self.outline_thickness)
|
outline_size = ray.ffi.new('float*', self.outline_thickness)
|
||||||
@@ -200,7 +201,7 @@ class OutlinedText:
|
|||||||
if reload_font:
|
if reload_font:
|
||||||
codepoint_count = ray.ffi.new('int *', 0)
|
codepoint_count = ray.ffi.new('int *', 0)
|
||||||
codepoints = ray.load_codepoints(''.join(global_data.font_codepoints), codepoint_count)
|
codepoints = ray.load_codepoints(''.join(global_data.font_codepoints), codepoint_count)
|
||||||
global_data.font = ray.load_font_ex(str(Path('Graphics/Modified-DFPKanteiryu-XB.ttf')), 40, codepoints, len(global_data.font_codepoints))
|
global_data.font = ray.load_font_ex(str(Path(f'Skins/{global_data.config["paths"]["skin"]}/Graphics/Modified-DFPKanteiryu-XB.ttf')), 40, codepoints, len(global_data.font_codepoints))
|
||||||
logger.info(f"Reloaded font with {len(global_data.font_codepoints)} codepoints")
|
logger.info(f"Reloaded font with {len(global_data.font_codepoints)} codepoints")
|
||||||
return global_data.font
|
return global_data.font
|
||||||
|
|
||||||
@@ -358,19 +359,25 @@ class OutlinedText:
|
|||||||
ray.unload_image(image)
|
ray.unload_image(image)
|
||||||
return texture
|
return texture
|
||||||
|
|
||||||
def _create_text_horizontal(self, text: str, font_size: int, color: ray.Color, bg_color: ray.Color, font: Optional[ray.Font]=None, padding: int=10):
|
def _create_text_horizontal(self, text: str, font_size: int, color: ray.Color, bg_color: ray.Color, font: Optional[ray.Font]=None, padding: int=10, spacing: int=1):
|
||||||
if font:
|
if font:
|
||||||
text_size = ray.measure_text_ex(font, text, font_size, 0)
|
text_size = ray.measure_text_ex(font, text, font_size, spacing)
|
||||||
|
for char in text:
|
||||||
|
if char in string.whitespace:
|
||||||
|
text_size.x += 2
|
||||||
total_width = text_size.x + (padding * 2)
|
total_width = text_size.x + (padding * 2)
|
||||||
total_height = text_size.y + (padding * 2)
|
total_height = text_size.y + (padding * 2)
|
||||||
else:
|
else:
|
||||||
total_width = ray.measure_text(text, font_size) + (padding * 2)
|
total_width = ray.measure_text(text, font_size) + (padding * 2)
|
||||||
total_height = font_size + (padding * 2)
|
total_height = font_size + (padding * 2)
|
||||||
|
|
||||||
image = ray.gen_image_color(int(total_width), int(total_height), bg_color)
|
image = ray.gen_image_color(int(total_width), int(total_height), bg_color)
|
||||||
|
|
||||||
if font:
|
if font:
|
||||||
text_image = ray.image_text_ex(font, text, font_size, 0, color)
|
text_image = ray.image_text_ex(font, text, font_size, spacing, color)
|
||||||
else:
|
else:
|
||||||
text_image = ray.image_text(text, font_size, color)
|
text_image = ray.image_text(text, font_size, color)
|
||||||
|
|
||||||
text_x = padding
|
text_x = padding
|
||||||
text_y = padding
|
text_y = padding
|
||||||
ray.image_draw(image, text_image,
|
ray.image_draw(image, text_image,
|
||||||
@@ -378,7 +385,6 @@ class OutlinedText:
|
|||||||
ray.Rectangle(text_x, text_y, text_image.width, text_image.height),
|
ray.Rectangle(text_x, text_y, text_image.width, text_image.height),
|
||||||
ray.WHITE)
|
ray.WHITE)
|
||||||
ray.unload_image(text_image)
|
ray.unload_image(text_image)
|
||||||
|
|
||||||
ray.export_image(image, f'cache/image/{self.hash}.png')
|
ray.export_image(image, f'cache/image/{self.hash}.png')
|
||||||
texture = ray.load_texture_from_image(image)
|
texture = ray.load_texture_from_image(image)
|
||||||
ray.unload_image(image)
|
ray.unload_image(image)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
from pathlib import Path
|
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import raylib as ray
|
|
||||||
import av
|
import av
|
||||||
|
import raylib as ray
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.utils import get_current_ms
|
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
|
from libs.utils import get_current_ms
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "pytaiko"
|
name = "pytaiko"
|
||||||
version = "1.0"
|
version = "1.1"
|
||||||
description = "Taiko no Tatsujin simulator written in python and raylib"
|
description = "Taiko no Tatsujin simulator written in python and raylib"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
|
from libs.audio import audio
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.global_data import PlayerNum, reset_session
|
from libs.global_data import PlayerNum, reset_session
|
||||||
from libs.audio import audio
|
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate
|
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
@@ -13,7 +14,7 @@ from libs.utils import (
|
|||||||
get_current_ms,
|
get_current_ms,
|
||||||
global_data,
|
global_data,
|
||||||
is_l_don_pressed,
|
is_l_don_pressed,
|
||||||
is_r_don_pressed
|
is_r_don_pressed,
|
||||||
)
|
)
|
||||||
from scenes.game import Gauge
|
from scenes.game import Gauge
|
||||||
from scenes.result import Background
|
from scenes.result import Background
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.global_data import PlayerNum, global_data
|
|
||||||
from libs.texture import tex
|
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Indicator, Nameplate, Timer
|
|
||||||
from libs.screen import Screen
|
|
||||||
from libs.file_navigator import BackBox, DanCourse, navigator
|
from libs.file_navigator import BackBox, DanCourse, navigator
|
||||||
|
from libs.global_data import PlayerNum, global_data
|
||||||
|
from libs.global_objects import (
|
||||||
|
AllNetIcon,
|
||||||
|
CoinOverlay,
|
||||||
|
Indicator,
|
||||||
|
Nameplate,
|
||||||
|
Timer,
|
||||||
|
)
|
||||||
|
from libs.screen import Screen
|
||||||
|
from libs.texture import tex
|
||||||
from libs.transition import Transition
|
from libs.transition import Transition
|
||||||
from libs.utils import get_current_ms, is_l_don_pressed, is_l_kat_pressed, is_r_don_pressed, is_r_kat_pressed
|
from libs.utils import (
|
||||||
|
get_current_ms,
|
||||||
|
is_l_don_pressed,
|
||||||
|
is_l_kat_pressed,
|
||||||
|
is_r_don_pressed,
|
||||||
|
is_r_kat_pressed,
|
||||||
|
)
|
||||||
from scenes.song_select import State
|
from scenes.song_select import State
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|||||||
@@ -1,18 +1,33 @@
|
|||||||
import copy
|
import copy
|
||||||
from typing import Optional, override
|
|
||||||
import pyray as ray
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional, override
|
||||||
|
|
||||||
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.background import Background
|
from libs.background import Background
|
||||||
from libs.file_navigator import Exam
|
from libs.file_navigator import Exam
|
||||||
from libs.global_data import DanResultExam, DanResultSong, PlayerNum, global_data
|
from libs.global_data import (
|
||||||
|
DanResultExam,
|
||||||
|
DanResultSong,
|
||||||
|
PlayerNum,
|
||||||
|
global_data,
|
||||||
|
)
|
||||||
from libs.global_objects import AllNetIcon
|
from libs.global_objects import AllNetIcon
|
||||||
|
from libs.texture import tex
|
||||||
from libs.tja import TJAParser
|
from libs.tja import TJAParser
|
||||||
from libs.transition import Transition
|
from libs.transition import Transition
|
||||||
from libs.utils import OutlinedText, get_current_ms
|
from libs.utils import OutlinedText, get_current_ms
|
||||||
from libs.texture import tex
|
from scenes.game import (
|
||||||
from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, Gauge, ResultTransition, SongInfo
|
ClearAnimation,
|
||||||
|
FailAnimation,
|
||||||
|
FCAnimation,
|
||||||
|
GameScreen,
|
||||||
|
Gauge,
|
||||||
|
ResultTransition,
|
||||||
|
SongInfo,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate, Indicator, EntryOverlay, Timer
|
from libs.global_objects import (
|
||||||
from libs.texture import tex
|
AllNetIcon,
|
||||||
|
CoinOverlay,
|
||||||
|
EntryOverlay,
|
||||||
|
Indicator,
|
||||||
|
Nameplate,
|
||||||
|
Timer,
|
||||||
|
)
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
|
from libs.texture import tex
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
OutlinedText,
|
OutlinedText,
|
||||||
get_current_ms,
|
get_current_ms,
|
||||||
@@ -439,9 +447,9 @@ class BoxManager:
|
|||||||
"""BoxManager class for the entry screen"""
|
"""BoxManager class for the entry screen"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.box_titles: list[OutlinedText] = [
|
self.box_titles: list[OutlinedText] = [
|
||||||
OutlinedText('演奏ゲーム', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
|
OutlinedText(tex.skin_config["entry_game"].text[global_data.config["general"]["language"]], tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
|
||||||
OutlinedText('特訓モード', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
|
OutlinedText(tex.skin_config["entry_practice"].text[global_data.config["general"]["language"]], tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
|
||||||
OutlinedText('ゲーム設定', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True)]
|
OutlinedText(tex.skin_config["entry_settings"].text[global_data.config["general"]["language"]], tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True)]
|
||||||
self.box_locations = ["SONG_SELECT", "PRACTICE_SELECT", "SETTINGS"]
|
self.box_locations = ["SONG_SELECT", "PRACTICE_SELECT", "SETTINGS"]
|
||||||
self.num_boxes = len(self.box_titles)
|
self.num_boxes = len(self.box_titles)
|
||||||
self.boxes = [Box(self.box_titles[i], self.box_locations[i]) for i in range(len(self.box_titles))]
|
self.boxes = [Box(self.box_titles[i], self.box_locations[i]) for i in range(len(self.box_titles))]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import bisect
|
import bisect
|
||||||
from enum import IntEnum
|
|
||||||
import math
|
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
from enum import IntEnum
|
||||||
|
from itertools import chain
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from itertools import chain
|
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
@@ -14,7 +14,13 @@ from libs.animation import Animation
|
|||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.background import Background
|
from libs.background import Background
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.global_data import Crown, Difficulty, Modifiers, PlayerNum, ScoreMethod
|
from libs.global_data import (
|
||||||
|
Crown,
|
||||||
|
Difficulty,
|
||||||
|
Modifiers,
|
||||||
|
PlayerNum,
|
||||||
|
ScoreMethod,
|
||||||
|
)
|
||||||
from libs.global_objects import AllNetIcon, Nameplate
|
from libs.global_objects import AllNetIcon, Nameplate
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
@@ -24,8 +30,8 @@ from libs.tja import (
|
|||||||
Note,
|
Note,
|
||||||
NoteList,
|
NoteList,
|
||||||
NoteType,
|
NoteType,
|
||||||
TJAParser,
|
|
||||||
TimelineObject,
|
TimelineObject,
|
||||||
|
TJAParser,
|
||||||
apply_modifiers,
|
apply_modifiers,
|
||||||
calculate_base_score,
|
calculate_base_score,
|
||||||
)
|
)
|
||||||
@@ -116,7 +122,7 @@ class GameScreen(Screen):
|
|||||||
|
|
||||||
def load_hitsounds(self):
|
def load_hitsounds(self):
|
||||||
"""Load the hit sounds"""
|
"""Load the hit sounds"""
|
||||||
sounds_dir = Path("Sounds")
|
sounds_dir = Path(f"Skins/{global_data.config["paths"]["skin"]}/Sounds")
|
||||||
if global_data.hit_sound == -1:
|
if global_data.hit_sound == -1:
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_don_1p')
|
audio.load_sound(Path('none.wav'), 'hitsound_don_1p')
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_kat_1p')
|
audio.load_sound(Path('none.wav'), 'hitsound_kat_1p')
|
||||||
@@ -448,7 +454,7 @@ class Player:
|
|||||||
self.get_load_time(note)
|
self.get_load_time(note)
|
||||||
if note.type == NoteType.TAIL:
|
if note.type == NoteType.TAIL:
|
||||||
note.load_ms = last_note.load_ms
|
note.load_ms = last_note.load_ms
|
||||||
note.unload_ms = last_note.unload_ms
|
last_note.unload_ms = note.unload_ms
|
||||||
last_note = note
|
last_note = note
|
||||||
|
|
||||||
self.draw_note_list = deque(sorted(self.draw_note_list, key=lambda n: n.load_ms))
|
self.draw_note_list = deque(sorted(self.draw_note_list, key=lambda n: n.load_ms))
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
|
||||||
import threading
|
import threading
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
|
from libs.file_navigator import navigator
|
||||||
from libs.global_objects import AllNetIcon
|
from libs.global_objects import AllNetIcon
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
from libs.song_hash import build_song_hashes
|
from libs.song_hash import build_song_hashes
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.utils import get_current_ms, global_data
|
from libs.utils import get_current_ms, global_data
|
||||||
from libs.file_navigator import navigator
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -58,7 +57,7 @@ class LoadScreen(Screen):
|
|||||||
global_data.font_codepoints.add(character)
|
global_data.font_codepoints.add(character)
|
||||||
codepoint_count = ray.ffi.new('int *', 0)
|
codepoint_count = ray.ffi.new('int *', 0)
|
||||||
codepoints = ray.load_codepoints(''.join(global_data.font_codepoints), codepoint_count)
|
codepoints = ray.load_codepoints(''.join(global_data.font_codepoints), codepoint_count)
|
||||||
global_data.font = ray.load_font_ex(str(Path('Graphics/Modified-DFPKanteiryu-XB.ttf')), 40, codepoints, len(global_data.font_codepoints))
|
global_data.font = ray.load_font_ex(str(Path(f'Skins/{global_data.config["paths"]["skin"]}/Graphics/Modified-DFPKanteiryu-XB.ttf')), 40, codepoints, len(global_data.font_codepoints))
|
||||||
|
|
||||||
def _load_navigator(self):
|
def _load_navigator(self):
|
||||||
"""Background thread function to load navigator"""
|
"""Background thread function to load navigator"""
|
||||||
|
|||||||
@@ -1,20 +1,41 @@
|
|||||||
|
import copy
|
||||||
|
import logging
|
||||||
import math
|
import math
|
||||||
from collections import deque
|
from collections import deque
|
||||||
import logging
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
import copy
|
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.background import Background
|
from libs.background import Background
|
||||||
from libs.global_data import Modifiers, PlayerNum, global_data
|
from libs.global_data import Modifiers, PlayerNum, global_data
|
||||||
from libs.tja import Balloon, Drumroll, NoteType, TJAParser, TimelineObject, apply_modifiers
|
|
||||||
from libs.utils import get_current_ms, is_l_don_pressed, is_l_kat_pressed, is_r_don_pressed, is_r_kat_pressed
|
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from scenes.game import DrumHitEffect, DrumType, GameScreen, JudgeCounter, LaneHitEffect, Player, Side
|
from libs.tja import (
|
||||||
|
Balloon,
|
||||||
|
Drumroll,
|
||||||
|
NoteType,
|
||||||
|
TimelineObject,
|
||||||
|
TJAParser,
|
||||||
|
apply_modifiers,
|
||||||
|
)
|
||||||
|
from libs.utils import (
|
||||||
|
get_current_ms,
|
||||||
|
is_l_don_pressed,
|
||||||
|
is_l_kat_pressed,
|
||||||
|
is_r_don_pressed,
|
||||||
|
is_r_kat_pressed,
|
||||||
|
)
|
||||||
|
from scenes.game import (
|
||||||
|
DrumHitEffect,
|
||||||
|
DrumType,
|
||||||
|
GameScreen,
|
||||||
|
JudgeCounter,
|
||||||
|
LaneHitEffect,
|
||||||
|
Player,
|
||||||
|
Side,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.global_data import Difficulty, PlayerNum, reset_session
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
|
from libs.global_data import Difficulty, PlayerNum, reset_session
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate
|
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
@@ -12,7 +13,7 @@ from libs.utils import (
|
|||||||
get_current_ms,
|
get_current_ms,
|
||||||
global_data,
|
global_data,
|
||||||
is_l_don_pressed,
|
is_l_don_pressed,
|
||||||
is_r_don_pressed
|
is_r_don_pressed,
|
||||||
)
|
)
|
||||||
from scenes.game import ScoreMethod
|
from scenes.game import ScoreMethod
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
|
from libs.config import save_config
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
@@ -11,7 +13,6 @@ from libs.utils import (
|
|||||||
is_r_don_pressed,
|
is_r_don_pressed,
|
||||||
is_r_kat_pressed,
|
is_r_kat_pressed,
|
||||||
)
|
)
|
||||||
from libs.config import save_config
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,31 @@
|
|||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
from dataclasses import fields
|
from dataclasses import fields
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
import logging
|
|
||||||
|
|
||||||
from raylib import SHADER_UNIFORM_VEC3
|
from raylib import SHADER_UNIFORM_VEC3
|
||||||
|
|
||||||
from libs.file_navigator import DEFAULT_COLORS, BackBox, DanCourse, GenreIndex, navigator
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.file_navigator import Directory, SongBox, SongFile
|
from libs.file_navigator import (
|
||||||
|
DEFAULT_COLORS,
|
||||||
|
BackBox,
|
||||||
|
DanCourse,
|
||||||
|
Directory,
|
||||||
|
GenreIndex,
|
||||||
|
SongBox,
|
||||||
|
SongFile,
|
||||||
|
navigator,
|
||||||
|
)
|
||||||
from libs.global_data import Difficulty, Modifiers, PlayerNum
|
from libs.global_data import Difficulty, Modifiers, PlayerNum
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate, Indicator, Timer
|
from libs.global_objects import (
|
||||||
|
AllNetIcon,
|
||||||
|
CoinOverlay,
|
||||||
|
Indicator,
|
||||||
|
Nameplate,
|
||||||
|
Timer,
|
||||||
|
)
|
||||||
from libs.screen import Screen
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.transition import Transition
|
from libs.transition import Transition
|
||||||
@@ -69,6 +82,8 @@ class SongSelectScreen(Screen):
|
|||||||
self.dan_transition = DanTransition()
|
self.dan_transition = DanTransition()
|
||||||
self.shader = ray.load_shader('shader/dummy.vs', 'shader/colortransform.fs')
|
self.shader = ray.load_shader('shader/dummy.vs', 'shader/colortransform.fs')
|
||||||
self.color = None
|
self.color = None
|
||||||
|
song_format = tex.skin_config["song_num"].text[global_data.config["general"]["language"]]
|
||||||
|
self.song_num = OutlinedText(song_format.format(global_data.songs_played+1), tex.skin_config["song_num"].font_size, ray.WHITE)
|
||||||
self.load_shader_values(self.color)
|
self.load_shader_values(self.color)
|
||||||
|
|
||||||
session_data = global_data.session_data[global_data.player_num]
|
session_data = global_data.session_data[global_data.player_num]
|
||||||
@@ -387,8 +402,8 @@ class SongSelectScreen(Screen):
|
|||||||
|
|
||||||
self.indicator.draw(tex.skin_config['song_select_indicator'].x, tex.skin_config['song_select_indicator'].y)
|
self.indicator.draw(tex.skin_config['song_select_indicator'].x, tex.skin_config['song_select_indicator'].y)
|
||||||
|
|
||||||
tex.draw_texture('global', 'song_num_bg', fade=0.75)
|
tex.draw_texture('global', 'song_num_bg', fade=0.75, x=-(self.song_num.texture.width-127), x2=(self.song_num.texture.width-127))
|
||||||
tex.draw_texture('global', 'song_num', frame=global_data.songs_played % 4)
|
self.song_num.draw(ray.BLACK, x=tex.skin_config["song_num"].x-self.song_num.texture.width, y=tex.skin_config["song_num"].y)
|
||||||
if self.state == State.BROWSING or self.state == State.DIFF_SORTING:
|
if self.state == State.BROWSING or self.state == State.DIFF_SORTING:
|
||||||
self.timer_browsing.draw()
|
self.timer_browsing.draw()
|
||||||
elif self.state == State.SONG_SELECTED:
|
elif self.state == State.SONG_SELECTED:
|
||||||
@@ -478,13 +493,14 @@ class SongSelectPlayer:
|
|||||||
audio.play_sound('skip', 'sound')
|
audio.play_sound('skip', 'sound')
|
||||||
return "skip_right"
|
return "skip_right"
|
||||||
|
|
||||||
|
wheel = ray.get_mouse_wheel_move()
|
||||||
# Navigate left
|
# Navigate left
|
||||||
if is_l_kat_pressed(self.player_num):
|
if is_l_kat_pressed(self.player_num) or wheel > 0:
|
||||||
audio.play_sound('kat', 'sound')
|
audio.play_sound('kat', 'sound')
|
||||||
return "navigate_left"
|
return "navigate_left"
|
||||||
|
|
||||||
# Navigate right
|
# Navigate right
|
||||||
if is_r_kat_pressed(self.player_num):
|
if is_r_kat_pressed(self.player_num) or wheel < 0:
|
||||||
audio.play_sound('kat', 'sound')
|
audio.play_sound('kat', 'sound')
|
||||||
return "navigate_right"
|
return "navigate_right"
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ import logging
|
|||||||
import random
|
import random
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pyray as ray
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, EntryOverlay
|
from libs.global_objects import AllNetIcon, CoinOverlay, EntryOverlay
|
||||||
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
|
OutlinedText,
|
||||||
get_current_ms,
|
get_current_ms,
|
||||||
global_data,
|
global_data,
|
||||||
global_tex,
|
global_tex,
|
||||||
@@ -13,7 +17,6 @@ from libs.utils import (
|
|||||||
is_r_don_pressed,
|
is_r_don_pressed,
|
||||||
)
|
)
|
||||||
from libs.video import VideoPlayer
|
from libs.video import VideoPlayer
|
||||||
from libs.screen import Screen
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -25,19 +28,11 @@ class State:
|
|||||||
class TitleScreen(Screen):
|
class TitleScreen(Screen):
|
||||||
def __init__(self, name: str):
|
def __init__(self, name: str):
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
#normalize to accept both stings and lists in toml
|
|
||||||
#maybe normalize centrally? but it's used only here
|
|
||||||
vp = global_data.config["paths"]["video_path"]
|
|
||||||
video_paths = [vp] if isinstance(vp, str) else vp
|
|
||||||
self.op_video_list = []
|
self.op_video_list = []
|
||||||
self.attract_video_list = []
|
self.attract_video_list = []
|
||||||
for base in video_paths:
|
base = Path(f"Skins/{global_data.config["paths"]["skin"]}/Videos")
|
||||||
base = Path(base)
|
self.op_video_list += list((base/"op_videos").glob("**/*.mp4"))
|
||||||
self.op_video_list += list((base/"op_videos").glob("**/*.mp4"))
|
self.attract_video_list += list((base/"attract_videos").glob("**/*.mp4"))
|
||||||
self.attract_video_list += list((base/"attract_videos").glob("**/*.mp4"))
|
|
||||||
self.coin_overlay = CoinOverlay()
|
|
||||||
self.allnet_indicator = AllNetIcon()
|
|
||||||
self.entry_overlay = EntryOverlay()
|
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
super().on_screen_start()
|
super().on_screen_start()
|
||||||
@@ -45,6 +40,10 @@ class TitleScreen(Screen):
|
|||||||
self.op_video = None
|
self.op_video = None
|
||||||
self.attract_video = None
|
self.attract_video = None
|
||||||
self.warning_board = None
|
self.warning_board = None
|
||||||
|
self.coin_overlay = CoinOverlay()
|
||||||
|
self.allnet_indicator = AllNetIcon()
|
||||||
|
self.entry_overlay = EntryOverlay()
|
||||||
|
self.hit_taiko_text = OutlinedText(global_tex.skin_config["hit_taiko_to_start"].text[global_data.config["general"]["language"]], tex.skin_config["hit_taiko_to_start"].font_size, ray.WHITE, spacing=5)
|
||||||
self.fade_out = tex.get_animation(13)
|
self.fade_out = tex.get_animation(13)
|
||||||
self.text_overlay_fade = tex.get_animation(14)
|
self.text_overlay_fade = tex.get_animation(14)
|
||||||
|
|
||||||
@@ -121,8 +120,8 @@ class TitleScreen(Screen):
|
|||||||
self.allnet_indicator.draw()
|
self.allnet_indicator.draw()
|
||||||
self.entry_overlay.draw(tex.skin_config["entry_overlay_title"].x, y=tex.skin_config["entry_overlay_title"].y)
|
self.entry_overlay.draw(tex.skin_config["entry_overlay_title"].x, y=tex.skin_config["entry_overlay_title"].y)
|
||||||
|
|
||||||
global_tex.draw_texture('overlay', 'hit_taiko_to_start', index=0, fade=self.text_overlay_fade.attribute)
|
self.hit_taiko_text.draw(ray.BLACK, x=tex.screen_width*0.25 - self.hit_taiko_text.texture.width//2, y=tex.skin_config["hit_taiko_to_start"].y, fade=self.text_overlay_fade.attribute)
|
||||||
global_tex.draw_texture('overlay', 'hit_taiko_to_start', index=1, fade=self.text_overlay_fade.attribute)
|
self.hit_taiko_text.draw(ray.BLACK, x=tex.screen_width*0.75 - self.hit_taiko_text.texture.width//2, y=tex.skin_config["hit_taiko_to_start"].y, fade=self.text_overlay_fade.attribute)
|
||||||
|
|
||||||
class WarningScreen:
|
class WarningScreen:
|
||||||
"""Warning screen for the game"""
|
"""Warning screen for the game"""
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
import logging
|
|
||||||
import copy
|
import copy
|
||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pyray as ray
|
||||||
|
|
||||||
|
from libs.audio import audio
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.tja import TJAParser
|
from libs.tja import TJAParser
|
||||||
from libs.utils import get_current_ms
|
from libs.utils import get_current_ms, global_data
|
||||||
from libs.audio import audio
|
|
||||||
from libs.utils import global_data
|
|
||||||
from libs.video import VideoPlayer
|
from libs.video import VideoPlayer
|
||||||
import pyray as ray
|
from scenes.game import (
|
||||||
from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, Player, Background, ResultTransition
|
Background,
|
||||||
|
ClearAnimation,
|
||||||
|
FailAnimation,
|
||||||
|
FCAnimation,
|
||||||
|
GameScreen,
|
||||||
|
Player,
|
||||||
|
ResultTransition,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -23,7 +32,7 @@ class TwoPlayerGameScreen(GameScreen):
|
|||||||
|
|
||||||
def load_hitsounds(self):
|
def load_hitsounds(self):
|
||||||
"""Load the hit sounds"""
|
"""Load the hit sounds"""
|
||||||
sounds_dir = Path("Sounds")
|
sounds_dir = Path(f"Skins/{global_data.config["paths"]["skin"]}/Sounds")
|
||||||
|
|
||||||
# Load hitsounds for 1P
|
# Load hitsounds for 1P
|
||||||
if global_data.hit_sound[PlayerNum.P1] == -1:
|
if global_data.hit_sound[PlayerNum.P1] == -1:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.utils import get_current_ms
|
from libs.utils import get_current_ms
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from libs.audio import audio
|
||||||
from libs.file_navigator import SongBox, SongFile
|
from libs.file_navigator import SongBox, SongFile
|
||||||
from libs.global_data import PlayerNum
|
from libs.global_data import PlayerNum
|
||||||
from libs.transition import Transition
|
from libs.transition import Transition
|
||||||
from scenes.song_select import DiffSortSelect, SongSelectPlayer, SongSelectScreen, State
|
|
||||||
from libs.utils import get_current_ms, global_data
|
from libs.utils import get_current_ms, global_data
|
||||||
from libs.audio import audio
|
from scenes.song_select import (
|
||||||
|
DiffSortSelect,
|
||||||
|
SongSelectPlayer,
|
||||||
|
SongSelectScreen,
|
||||||
|
State,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user