mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
Add 2P
This commit is contained in:
10
PyTaiko.py
10
PyTaiko.py
@@ -20,11 +20,13 @@ from scenes.devtest import DevScreen
|
||||
from scenes.entry import EntryScreen
|
||||
from scenes.game import GameScreen
|
||||
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.settings import SettingsScreen
|
||||
from scenes.song_select import SongSelectScreen
|
||||
from scenes.title import TitleScreen
|
||||
from scenes.two_player.song_select import TwoPlayerSongSelectScreen
|
||||
|
||||
|
||||
class Screens:
|
||||
@@ -34,6 +36,8 @@ class Screens:
|
||||
GAME = "GAME"
|
||||
GAME_2P = "GAME_2P"
|
||||
RESULT = "RESULT"
|
||||
RESULT_2P = "RESULT_2P"
|
||||
SONG_SELECT_2P = "SONG_SELECT_2P"
|
||||
SETTINGS = "SETTINGS"
|
||||
DEV_MENU = "DEV_MENU"
|
||||
LOADING = "LOADING"
|
||||
@@ -107,10 +111,12 @@ def main():
|
||||
title_screen = TitleScreen()
|
||||
entry_screen = EntryScreen()
|
||||
song_select_screen = SongSelectScreen()
|
||||
load_screen = LoadScreen(song_select_screen)
|
||||
song_select_screen_2p = TwoPlayerSongSelectScreen()
|
||||
load_screen = LoadScreen()
|
||||
game_screen = GameScreen()
|
||||
game_screen_2p = TwoPlayerGameScreen()
|
||||
result_screen = ResultScreen()
|
||||
result_screen_2p = TwoPlayerResultScreen()
|
||||
settings_screen = SettingsScreen()
|
||||
dev_screen = DevScreen()
|
||||
|
||||
@@ -118,9 +124,11 @@ def main():
|
||||
Screens.ENTRY: entry_screen,
|
||||
Screens.TITLE: title_screen,
|
||||
Screens.SONG_SELECT: song_select_screen,
|
||||
Screens.SONG_SELECT_2P: song_select_screen_2p,
|
||||
Screens.GAME: game_screen,
|
||||
Screens.GAME_2P: game_screen_2p,
|
||||
Screens.RESULT: result_screen,
|
||||
Screens.RESULT_2P: result_screen_2p,
|
||||
Screens.SETTINGS: settings_screen,
|
||||
Screens.DEV_MENU: dev_screen,
|
||||
Screens.LOADING: load_screen
|
||||
|
||||
@@ -8,12 +8,18 @@ touch_enabled = false
|
||||
timer_frozen = true
|
||||
judge_counter = false
|
||||
|
||||
[nameplate]
|
||||
[nameplate_1p]
|
||||
name = 'どんちゃん'
|
||||
title = 'ドンだーデビュー!'
|
||||
dan = -1
|
||||
gold = false
|
||||
|
||||
[nameplate_2p]
|
||||
name = 'かつちゃん'
|
||||
title = 'ドンだーデビュー!'
|
||||
dan = -1
|
||||
gold = false
|
||||
|
||||
[paths]
|
||||
tja_path = ['Songs']
|
||||
video_path = ['Videos']
|
||||
|
||||
1327
libs/file_navigator.py
Normal file
1327
libs/file_navigator.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,32 @@ class Modifiers:
|
||||
inverse: bool = False
|
||||
random: int = 0
|
||||
|
||||
@dataclass
|
||||
class SessionData:
|
||||
"""Data class for storing session data. Wiped after the result screen.
|
||||
selected_difficulty: The difficulty level selected by the user.
|
||||
song_title: The title of the song being played.
|
||||
genre_index: The index of the genre being played.
|
||||
result_score: The score achieved in the game.
|
||||
result_good: The number of good notes achieved in the game.
|
||||
result_ok: The number of ok notes achieved in the game.
|
||||
result_bad: The number of bad notes achieved in the game.
|
||||
result_max_combo: The maximum combo achieved in the game.
|
||||
result_total_drumroll: The total drumroll achieved in the game.
|
||||
result_gauge_length: The length of the gauge achieved in the game.
|
||||
prev_score: The previous score pulled from the database."""
|
||||
selected_difficulty: int = 0
|
||||
song_title: str = ''
|
||||
genre_index: int = 0
|
||||
result_score: int = 0
|
||||
result_good: int = 0
|
||||
result_ok: int = 0
|
||||
result_bad: int = 0
|
||||
result_max_combo: int = 0
|
||||
result_total_drumroll: int = 0
|
||||
result_gauge_length: int = 0
|
||||
prev_score: int = 0
|
||||
|
||||
@dataclass
|
||||
class GlobalData:
|
||||
"""
|
||||
@@ -26,10 +52,11 @@ class GlobalData:
|
||||
song_paths (dict[Path, str]): A dictionary mapping song paths to their hashes.
|
||||
song_progress (float): The progress of the loading bar.
|
||||
total_songs (int): The total number of songs.
|
||||
hit_sound (int): The index of the hit sound currently used.
|
||||
hit_sound (list[int]): The indices of the hit sounds currently used.
|
||||
player_num (int): The player number. Either 1 or 2.
|
||||
input_locked (int): The input lock status. 0 means unlocked, 1 or greater means locked.
|
||||
modifiers (Modifiers): The modifiers for the game.
|
||||
modifiers (list[Modifiers]): The modifiers for the game.
|
||||
session_data (list[SessionData]): Session data for both players.
|
||||
"""
|
||||
selected_song: Path = Path()
|
||||
songs_played: int = 0
|
||||
@@ -38,9 +65,15 @@ class GlobalData:
|
||||
song_paths: dict[Path, str] = field(default_factory=lambda: dict()) #path to hash
|
||||
song_progress: float = 0.0
|
||||
total_songs: int = 0
|
||||
hit_sound: int = 0
|
||||
hit_sound: list[int] = field(default_factory=lambda: [0, 0])
|
||||
player_num: int = 1
|
||||
input_locked: int = 0
|
||||
modifiers: Modifiers = field(default_factory=lambda: Modifiers())
|
||||
modifiers: list[Modifiers] = field(default_factory=lambda: [Modifiers(), Modifiers()])
|
||||
session_data: list[SessionData] = field(default_factory=lambda: [SessionData(), SessionData()])
|
||||
|
||||
global_data = GlobalData()
|
||||
|
||||
def reset_session():
|
||||
"""Reset the session data."""
|
||||
global_data.session_data[0] = SessionData()
|
||||
global_data.session_data[1] = SessionData()
|
||||
|
||||
@@ -4,7 +4,6 @@ import math
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from libs.global_data import global_data
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
@@ -92,11 +91,16 @@ def save_config(config: dict[str, Any]) -> None:
|
||||
with open(Path('config.toml'), "w", encoding="utf-8") as f:
|
||||
tomlkit.dump(config, f)
|
||||
|
||||
def is_l_don_pressed() -> bool:
|
||||
def is_l_don_pressed(player_num: str = '0') -> bool:
|
||||
"""Check if the left don button is pressed"""
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
if player_num == '0':
|
||||
keys = global_data.config["keys_1p"]["left_don"] + global_data.config["keys_2p"]["left_don"]
|
||||
elif player_num == '1':
|
||||
keys = global_data.config["keys_1p"]["left_don"]
|
||||
elif player_num == '2':
|
||||
keys = global_data.config["keys_2p"]["left_don"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["left_don"]
|
||||
for key in keys:
|
||||
if ray.is_key_pressed(ord(key)):
|
||||
@@ -117,11 +121,16 @@ def is_l_don_pressed() -> bool:
|
||||
|
||||
return False
|
||||
|
||||
def is_r_don_pressed() -> bool:
|
||||
def is_r_don_pressed(player_num: str = '0') -> bool:
|
||||
"""Check if the right don button is pressed"""
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
if player_num == '0':
|
||||
keys = global_data.config["keys_1p"]["right_don"] + global_data.config["keys_2p"]["right_don"]
|
||||
elif player_num == '1':
|
||||
keys = global_data.config["keys_1p"]["right_don"]
|
||||
elif player_num == '2':
|
||||
keys = global_data.config["keys_2p"]["right_don"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["right_don"]
|
||||
for key in keys:
|
||||
if ray.is_key_pressed(ord(key)):
|
||||
@@ -144,11 +153,16 @@ def is_r_don_pressed() -> bool:
|
||||
|
||||
return False
|
||||
|
||||
def is_l_kat_pressed() -> bool:
|
||||
def is_l_kat_pressed(player_num: str = '0') -> bool:
|
||||
"""Check if the left kat button is pressed"""
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
if player_num == '0':
|
||||
keys = global_data.config["keys_1p"]["left_kat"] + global_data.config["keys_2p"]["left_kat"]
|
||||
elif player_num == '1':
|
||||
keys = global_data.config["keys_1p"]["left_kat"]
|
||||
elif player_num == '2':
|
||||
keys = global_data.config["keys_2p"]["left_kat"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["left_kat"]
|
||||
for key in keys:
|
||||
if ray.is_key_pressed(ord(key)):
|
||||
@@ -171,11 +185,16 @@ def is_l_kat_pressed() -> bool:
|
||||
|
||||
return False
|
||||
|
||||
def is_r_kat_pressed() -> bool:
|
||||
def is_r_kat_pressed(player_num: str = '0') -> bool:
|
||||
"""Check if the right kat button is pressed"""
|
||||
if global_data.input_locked:
|
||||
return False
|
||||
if player_num == '0':
|
||||
keys = global_data.config["keys_1p"]["right_kat"] + global_data.config["keys_2p"]["right_kat"]
|
||||
elif player_num == '1':
|
||||
keys = global_data.config["keys_1p"]["right_kat"]
|
||||
elif player_num == '2':
|
||||
keys = global_data.config["keys_2p"]["right_kat"]
|
||||
gamepad_buttons = global_data.config["gamepad"]["right_kat"]
|
||||
for key in keys:
|
||||
if ray.is_key_pressed(ord(key)):
|
||||
@@ -198,39 +217,8 @@ def is_r_kat_pressed() -> bool:
|
||||
|
||||
return False
|
||||
|
||||
@dataclass
|
||||
class SessionData:
|
||||
"""Data class for storing session data. Wiped after the result screen.
|
||||
selected_difficulty: The difficulty level selected by the user.
|
||||
song_title: The title of the song being played.
|
||||
genre_index: The index of the genre being played.
|
||||
result_score: The score achieved in the game.
|
||||
result_good: The number of good notes achieved in the game.
|
||||
result_ok: The number of ok notes achieved in the game.
|
||||
result_bad: The number of bad notes achieved in the game.
|
||||
result_max_combo: The maximum combo achieved in the game.
|
||||
result_total_drumroll: The total drumroll achieved in the game.
|
||||
result_gauge_length: The length of the gauge achieved in the game.
|
||||
prev_score: The previous score pulled from the database."""
|
||||
selected_difficulty: int = 0
|
||||
song_title: str = ''
|
||||
genre_index: int = 0
|
||||
result_score: int = 0
|
||||
result_good: int = 0
|
||||
result_ok: int = 0
|
||||
result_bad: int = 0
|
||||
result_max_combo: int = 0
|
||||
result_total_drumroll: int = 0
|
||||
result_gauge_length: int = 0
|
||||
prev_score: int = 0
|
||||
|
||||
session_data = SessionData()
|
||||
global_tex = TextureWrapper()
|
||||
|
||||
def reset_session():
|
||||
"""Reset the session data."""
|
||||
return SessionData()
|
||||
|
||||
text_cache = set()
|
||||
if not Path('cache/image').exists():
|
||||
if not Path('cache').exists():
|
||||
|
||||
293
scenes/entry.py
293
scenes/entry.py
@@ -29,11 +29,14 @@ class EntryScreen:
|
||||
tex.load_screen_textures('entry')
|
||||
audio.load_screen_sounds('entry')
|
||||
self.side = 1
|
||||
self.is_2p = False
|
||||
self.box_manager = BoxManager()
|
||||
self.state = State.SELECT_SIDE
|
||||
plate_info = global_data.config['nameplate']
|
||||
|
||||
# Initial nameplate for side selection
|
||||
plate_info = global_data.config['nameplate_1p']
|
||||
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], -1, -1, False)
|
||||
self.indicator = Indicator(Indicator.State.SELECT)
|
||||
|
||||
self.coin_overlay = CoinOverlay()
|
||||
self.allnet_indicator = AllNetIcon()
|
||||
self.entry_overlay = EntryOverlay()
|
||||
@@ -41,93 +44,95 @@ class EntryScreen:
|
||||
self.screen_init = True
|
||||
self.side_select_fade = tex.get_animation(0)
|
||||
self.bg_flicker = tex.get_animation(1)
|
||||
self.drum_move_1 = tex.get_animation(2)
|
||||
self.drum_move_2 = tex.get_animation(3)
|
||||
self.drum_move_3 = tex.get_animation(4)
|
||||
self.cloud_resize = tex.get_animation(5)
|
||||
self.cloud_resize_loop = tex.get_animation(6)
|
||||
self.cloud_texture_change = tex.get_animation(7)
|
||||
self.cloud_fade = tex.get_animation(8)
|
||||
self.nameplate_fadein = tex.get_animation(12)
|
||||
self.side_select_fade.start()
|
||||
self.chara = Chara2D(0, 100)
|
||||
self.announce_played = False
|
||||
self.players = [None, None]
|
||||
audio.play_sound('bgm', 'music')
|
||||
|
||||
def on_screen_end(self, next_screen: str):
|
||||
self.screen_init = False
|
||||
audio.stop_sound('bgm')
|
||||
self.nameplate.unload()
|
||||
for player in self.players:
|
||||
if player:
|
||||
player.unload()
|
||||
tex.unload_textures()
|
||||
audio.unload_all_sounds()
|
||||
audio.unload_all_music()
|
||||
return next_screen
|
||||
|
||||
def handle_input(self):
|
||||
if self.box_manager.is_box_selected():
|
||||
return
|
||||
if self.state == State.SELECT_SIDE:
|
||||
if is_l_don_pressed() or is_r_don_pressed():
|
||||
if self.side == 1:
|
||||
return self.on_screen_end("TITLE")
|
||||
global_data.player_num = round((self.side/3) + 1)
|
||||
self.drum_move_1.start()
|
||||
self.drum_move_2.start()
|
||||
self.drum_move_3.start()
|
||||
self.cloud_resize.start()
|
||||
self.cloud_resize_loop.start()
|
||||
self.cloud_texture_change.start()
|
||||
self.cloud_fade.start()
|
||||
|
||||
if self.players[0]:
|
||||
self.players[1] = EntryPlayer(global_data.player_num, self.side, self.box_manager)
|
||||
self.players[1].start_animations()
|
||||
global_data.player_num = 1
|
||||
self.is_2p = True
|
||||
else:
|
||||
self.players[0] = EntryPlayer(global_data.player_num, self.side, self.box_manager)
|
||||
self.players[0].start_animations()
|
||||
self.is_2p = False
|
||||
|
||||
audio.play_sound('cloud', 'sound')
|
||||
audio.play_sound(f'entry_start_{global_data.player_num}p', 'voice')
|
||||
plate_info = global_data.config['nameplate']
|
||||
self.nameplate.unload()
|
||||
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], global_data.player_num, plate_info['dan'], plate_info['gold'])
|
||||
self.nameplate_fadein.start()
|
||||
self.state = State.SELECT_MODE
|
||||
if self.side == 2:
|
||||
self.chara = Chara2D(1, 100)
|
||||
else:
|
||||
self.chara = Chara2D(0, 100)
|
||||
audio.play_sound('don', 'sound')
|
||||
if is_l_kat_pressed():
|
||||
audio.play_sound('kat', 'sound')
|
||||
if self.players[0] and self.players[0].player_num == 1:
|
||||
self.side = 1
|
||||
elif self.players[0] and self.players[0].player_num == 2:
|
||||
self.side = 0
|
||||
else:
|
||||
self.side = max(0, self.side - 1)
|
||||
if is_r_kat_pressed():
|
||||
audio.play_sound('kat', 'sound')
|
||||
if self.players[0] and self.players[0].player_num == 1:
|
||||
self.side = 2
|
||||
elif self.players[0] and self.players[0].player_num == 2:
|
||||
self.side = 1
|
||||
else:
|
||||
self.side = min(2, self.side + 1)
|
||||
elif self.state == State.SELECT_MODE:
|
||||
if is_l_don_pressed() or is_r_don_pressed():
|
||||
for player in self.players:
|
||||
if player:
|
||||
player.handle_input()
|
||||
if self.players[0] and self.players[0].player_num == 1 and is_l_don_pressed('2') or is_r_don_pressed('2'):
|
||||
audio.play_sound('don', 'sound')
|
||||
self.box_manager.select_box()
|
||||
if is_l_kat_pressed():
|
||||
audio.play_sound('kat', 'sound')
|
||||
self.box_manager.move_left()
|
||||
if is_r_kat_pressed():
|
||||
audio.play_sound('kat', 'sound')
|
||||
self.box_manager.move_right()
|
||||
self.state = State.SELECT_SIDE
|
||||
plate_info = global_data.config['nameplate_2p']
|
||||
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], -1, -1, False)
|
||||
self.chara = Chara2D(1, 100)
|
||||
self.side_select_fade.restart()
|
||||
self.side = 1
|
||||
elif self.players[0] and self.players[0].player_num == 2 and is_l_don_pressed('1') or is_r_don_pressed('1'):
|
||||
audio.play_sound('don', 'sound')
|
||||
self.state = State.SELECT_SIDE
|
||||
self.side_select_fade.restart()
|
||||
self.side = 1
|
||||
|
||||
def update(self):
|
||||
self.on_screen_start()
|
||||
current_time = get_current_ms()
|
||||
self.side_select_fade.update(current_time)
|
||||
self.bg_flicker.update(current_time)
|
||||
self.drum_move_1.update(current_time)
|
||||
self.drum_move_2.update(current_time)
|
||||
self.drum_move_3.update(current_time)
|
||||
self.cloud_resize.update(current_time)
|
||||
self.cloud_texture_change.update(current_time)
|
||||
self.cloud_fade.update(current_time)
|
||||
self.cloud_resize_loop.update(current_time)
|
||||
self.box_manager.update(current_time)
|
||||
self.nameplate_fadein.update(current_time)
|
||||
self.nameplate.update(current_time)
|
||||
self.indicator.update(current_time)
|
||||
self.box_manager.update(current_time, self.is_2p)
|
||||
self.timer.update(current_time)
|
||||
self.nameplate.update(current_time)
|
||||
self.chara.update(current_time, 100, False, False)
|
||||
for player in self.players:
|
||||
if player:
|
||||
player.update(current_time)
|
||||
if self.box_manager.is_finished():
|
||||
return self.on_screen_end(self.box_manager.selected_box())
|
||||
if self.cloud_fade.is_finished and not audio.is_sound_playing(f'entry_start_{global_data.player_num}p') and not self.announce_played:
|
||||
for player in self.players:
|
||||
if player and player.cloud_fade.is_finished and not audio.is_sound_playing(f'entry_start_{global_data.player_num}p') and not self.announce_played:
|
||||
audio.play_sound('select_mode', 'voice')
|
||||
self.announce_played = True
|
||||
return self.handle_input()
|
||||
@@ -141,12 +146,6 @@ class EntryScreen:
|
||||
tex.draw_texture('background', 'shops_right')
|
||||
tex.draw_texture('background', 'lights', scale=2.0, fade=self.bg_flicker.attribute)
|
||||
|
||||
def draw_footer(self):
|
||||
tex.draw_texture('side_select', 'footer')
|
||||
if self.state == State.SELECT_SIDE or self.side != 0:
|
||||
tex.draw_texture('side_select', 'footer_left')
|
||||
if self.state == State.SELECT_SIDE or self.side != 2:
|
||||
tex.draw_texture('side_select', 'footer_right')
|
||||
|
||||
def draw_side_select(self, fade):
|
||||
tex.draw_texture('side_select', 'box_top_left', fade=fade)
|
||||
@@ -180,46 +179,38 @@ class EntryScreen:
|
||||
self.nameplate.draw(500, 185)
|
||||
|
||||
def draw_player_drum(self):
|
||||
move_x = self.drum_move_3.attribute
|
||||
move_y = self.drum_move_1.attribute + self.drum_move_2.attribute
|
||||
if self.side == 0:
|
||||
offset = 0
|
||||
tex.draw_texture('side_select', 'red_drum', x=move_x, y=move_y)
|
||||
else:
|
||||
move_x *= -1
|
||||
offset = 620
|
||||
tex.draw_texture('side_select', 'blue_drum', x=move_x, y=move_y)
|
||||
|
||||
scale = self.cloud_resize.attribute
|
||||
if self.cloud_resize.is_finished:
|
||||
scale = max(1, self.cloud_resize_loop.attribute)
|
||||
if self.side == 2:
|
||||
self.chara.draw(move_x + offset + 130, 570 + move_y, mirror=True)
|
||||
else:
|
||||
self.chara.draw(move_x + offset + 170, 570 + move_y)
|
||||
tex.draw_texture('side_select', 'cloud', x=move_x + offset, y=move_y, frame=self.cloud_texture_change.attribute, fade=self.cloud_fade.attribute, scale=scale, center=True)
|
||||
for player in self.players:
|
||||
if player:
|
||||
player.draw_drum()
|
||||
|
||||
def draw_mode_select(self):
|
||||
self.draw_player_drum()
|
||||
if not self.cloud_texture_change.is_finished:
|
||||
for player in self.players:
|
||||
if player and not player.is_cloud_animation_finished():
|
||||
return
|
||||
self.box_manager.draw()
|
||||
|
||||
def draw(self):
|
||||
self.draw_background()
|
||||
self.draw_player_drum()
|
||||
if self.state == State.SELECT_SIDE:
|
||||
self.draw_side_select(self.side_select_fade.attribute)
|
||||
elif self.state == State.SELECT_MODE:
|
||||
self.draw_mode_select()
|
||||
self.draw_footer()
|
||||
tex.draw_texture('side_select', 'footer')
|
||||
if self.players[0] and self.players[1]:
|
||||
pass
|
||||
elif not self.players[0]:
|
||||
tex.draw_texture('side_select', 'footer_left')
|
||||
tex.draw_texture('side_select', 'footer_right')
|
||||
elif self.players[0] and self.players[0].player_num == 1:
|
||||
tex.draw_texture('side_select', 'footer_right')
|
||||
elif self.players[0] and self.players[0].player_num == 2:
|
||||
tex.draw_texture('side_select', 'footer_left')
|
||||
|
||||
if self.state == State.SELECT_MODE:
|
||||
if self.side == 0:
|
||||
self.nameplate.draw(30, 640, fade=self.nameplate_fadein.attribute)
|
||||
self.indicator.draw(50, 575, fade=self.nameplate_fadein.attribute)
|
||||
else:
|
||||
self.nameplate.draw(950, 640, fade=self.nameplate_fadein.attribute)
|
||||
self.indicator.draw(770, 575, fade=self.nameplate_fadein.attribute)
|
||||
|
||||
for player in self.players:
|
||||
if player:
|
||||
player.draw_nameplate_and_indicator(fade=player.nameplate_fadein.attribute)
|
||||
|
||||
tex.draw_texture('global', 'player_entry')
|
||||
|
||||
@@ -231,8 +222,136 @@ class EntryScreen:
|
||||
self.coin_overlay.draw()
|
||||
self.allnet_indicator.draw()
|
||||
|
||||
def draw_3d(self):
|
||||
pass
|
||||
class EntryPlayer:
|
||||
"""Player-specific state and rendering for the entry screen"""
|
||||
def __init__(self, player_num: int, side: int, box_manager: 'BoxManager'):
|
||||
"""
|
||||
Initialize a player for the entry screen
|
||||
Args:
|
||||
player_num: 1 or 2 (player number)
|
||||
side: 0 for left (1P), 2 for right (2P)
|
||||
box_manager: Reference to the box manager for input handling
|
||||
"""
|
||||
self.player_num = player_num
|
||||
self.side = side
|
||||
self.box_manager = box_manager
|
||||
|
||||
# Load player-specific resources
|
||||
plate_info = global_data.config[f'nameplate_{self.player_num}p']
|
||||
self.nameplate = Nameplate(
|
||||
plate_info['name'],
|
||||
plate_info['title'],
|
||||
player_num,
|
||||
plate_info['dan'],
|
||||
plate_info['gold']
|
||||
)
|
||||
self.indicator = Indicator(Indicator.State.SELECT)
|
||||
|
||||
# Character (0 for red/1P, 1 for blue/2P)
|
||||
chara_id = 0 if side == 0 else 1
|
||||
self.chara = Chara2D(chara_id, 100)
|
||||
|
||||
# Animations
|
||||
self.drum_move_1 = tex.get_animation(2)
|
||||
self.drum_move_2 = tex.get_animation(3)
|
||||
self.drum_move_3 = tex.get_animation(4)
|
||||
self.cloud_resize = tex.get_animation(5)
|
||||
self.cloud_resize_loop = tex.get_animation(6)
|
||||
self.cloud_texture_change = tex.get_animation(7)
|
||||
self.cloud_fade = tex.get_animation(8)
|
||||
self.nameplate_fadein = tex.get_animation(12)
|
||||
|
||||
def start_animations(self):
|
||||
"""Start all player entry animations"""
|
||||
self.drum_move_1.start()
|
||||
self.drum_move_2.start()
|
||||
self.drum_move_3.start()
|
||||
self.cloud_resize.start()
|
||||
self.cloud_resize_loop.start()
|
||||
self.cloud_texture_change.start()
|
||||
self.cloud_fade.start()
|
||||
self.nameplate_fadein.start()
|
||||
|
||||
def update(self, current_time: float):
|
||||
"""Update player animations and state"""
|
||||
self.drum_move_1.update(current_time)
|
||||
self.drum_move_2.update(current_time)
|
||||
self.drum_move_3.update(current_time)
|
||||
self.cloud_resize.update(current_time)
|
||||
self.cloud_texture_change.update(current_time)
|
||||
self.cloud_fade.update(current_time)
|
||||
self.cloud_resize_loop.update(current_time)
|
||||
self.nameplate_fadein.update(current_time)
|
||||
self.nameplate.update(current_time)
|
||||
self.indicator.update(current_time)
|
||||
self.chara.update(current_time, 100, False, False)
|
||||
|
||||
def draw_drum(self):
|
||||
"""Draw the player's drum with animations"""
|
||||
move_x = self.drum_move_3.attribute
|
||||
move_y = self.drum_move_1.attribute + self.drum_move_2.attribute
|
||||
|
||||
if self.side == 0: # Left side (1P/red)
|
||||
offset = 0
|
||||
tex.draw_texture('side_select', 'red_drum', x=move_x, y=move_y)
|
||||
chara_x = move_x + offset + 170
|
||||
chara_mirror = False
|
||||
else: # Right side (2P/blue)
|
||||
move_x *= -1
|
||||
offset = 620
|
||||
tex.draw_texture('side_select', 'blue_drum', x=move_x, y=move_y)
|
||||
chara_x = move_x + offset + 130
|
||||
chara_mirror = True
|
||||
|
||||
# Draw character
|
||||
chara_y = 570 + move_y
|
||||
self.chara.draw(chara_x, chara_y, mirror=chara_mirror)
|
||||
|
||||
# Draw cloud
|
||||
scale = self.cloud_resize.attribute
|
||||
if self.cloud_resize.is_finished:
|
||||
scale = max(1, self.cloud_resize_loop.attribute)
|
||||
tex.draw_texture(
|
||||
'side_select', 'cloud',
|
||||
x=move_x + offset,
|
||||
y=move_y,
|
||||
frame=self.cloud_texture_change.attribute,
|
||||
fade=self.cloud_fade.attribute,
|
||||
scale=scale,
|
||||
center=True
|
||||
)
|
||||
|
||||
def draw_nameplate_and_indicator(self, fade: float = 1.0):
|
||||
"""Draw nameplate and indicator at player-specific position"""
|
||||
if self.side == 0: # Left side
|
||||
self.nameplate.draw(30, 640, fade=fade)
|
||||
self.indicator.draw(50, 575, fade=fade)
|
||||
else: # Right side
|
||||
self.nameplate.draw(950, 640, fade=fade)
|
||||
self.indicator.draw(770, 575, fade=fade)
|
||||
|
||||
def is_cloud_animation_finished(self) -> bool:
|
||||
"""Check if cloud texture change animation is finished"""
|
||||
return self.cloud_texture_change.is_finished
|
||||
|
||||
def unload(self):
|
||||
"""Unload player resources"""
|
||||
self.nameplate.unload()
|
||||
|
||||
def handle_input(self):
|
||||
"""Handle player input for mode selection"""
|
||||
if self.box_manager.is_box_selected():
|
||||
return
|
||||
|
||||
if is_l_don_pressed(str(self.player_num)) or is_r_don_pressed(str(self.player_num)):
|
||||
audio.play_sound('don', 'sound')
|
||||
self.box_manager.select_box()
|
||||
if is_l_kat_pressed(str(self.player_num)):
|
||||
audio.play_sound('kat', 'sound')
|
||||
self.box_manager.move_left()
|
||||
if is_r_kat_pressed(str(self.player_num)):
|
||||
audio.play_sound('kat', 'sound')
|
||||
self.box_manager.move_right()
|
||||
|
||||
class Box:
|
||||
"""Box class for the entry screen"""
|
||||
@@ -330,6 +449,7 @@ class BoxManager:
|
||||
self.boxes = [Box(self.box_titles[i], self.box_locations[i]) for i in range(len(self.box_titles))]
|
||||
self.selected_box_index = 0
|
||||
self.fade_out = tex.get_animation(9)
|
||||
self.is_2p = False
|
||||
|
||||
spacing = 80
|
||||
box_width = self.boxes[0].texture.width
|
||||
@@ -380,7 +500,12 @@ class BoxManager:
|
||||
self.boxes[self.selected_box_index-1].move_left()
|
||||
self.boxes[self.selected_box_index].move_left()
|
||||
|
||||
def update(self, current_time_ms: float):
|
||||
def update(self, current_time_ms: float, is_2p: bool):
|
||||
self.is_2p = is_2p
|
||||
if self.is_2p:
|
||||
self.box_locations = ["SONG_SELECT_2P", "SETTINGS"]
|
||||
for i, box in enumerate(self.boxes):
|
||||
box.location = self.box_locations[i]
|
||||
self.fade_out.update(current_time_ms)
|
||||
for i, box in enumerate(self.boxes):
|
||||
is_selected = i == self.selected_box_index
|
||||
|
||||
@@ -33,8 +33,7 @@ from libs.utils import (
|
||||
is_l_kat_pressed,
|
||||
is_r_don_pressed,
|
||||
is_r_kat_pressed,
|
||||
rounded,
|
||||
session_data,
|
||||
rounded
|
||||
)
|
||||
from libs.video import VideoPlayer
|
||||
|
||||
@@ -57,20 +56,14 @@ class GameScreen:
|
||||
if global_data.hit_sound == -1:
|
||||
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_don_2p')
|
||||
audio.load_sound(Path('none.wav'), 'hitsound_kat_2p')
|
||||
if global_data.hit_sound == 0:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.wav", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.wav", 'hitsound_kat_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.wav", 'hitsound_don_2p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.wav", 'hitsound_kat_2p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.wav", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.wav", 'hitsound_kat_1p')
|
||||
else:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.ogg", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.ogg", 'hitsound_kat_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.ogg", 'hitsound_don_2p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.ogg", 'hitsound_kat_2p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.ogg", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.ogg", 'hitsound_kat_1p')
|
||||
|
||||
def init_tja(self, song: Path, difficulty: int):
|
||||
def init_tja(self, song: Path):
|
||||
"""Initialize the TJA file"""
|
||||
self.tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X)
|
||||
if self.tja.metadata.bgmovie != Path() and self.tja.metadata.bgmovie.exists():
|
||||
@@ -78,11 +71,11 @@ class GameScreen:
|
||||
self.movie.set_volume(0.0)
|
||||
else:
|
||||
self.movie = None
|
||||
session_data.song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
|
||||
global_data.session_data[0].song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
|
||||
if self.tja.metadata.wave.exists() and self.tja.metadata.wave.is_file() and self.song_music is None:
|
||||
self.song_music = audio.load_music_stream(self.tja.metadata.wave, 'song')
|
||||
|
||||
self.player_1 = Player(self.tja, global_data.player_num, difficulty, False, global_data.modifiers)
|
||||
self.player_1 = Player(self.tja, global_data.player_num, global_data.session_data[global_data.player_num-1].selected_difficulty, False, global_data.modifiers[0])
|
||||
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
|
||||
|
||||
def on_screen_start(self):
|
||||
@@ -94,7 +87,8 @@ class GameScreen:
|
||||
audio.load_screen_sounds('game')
|
||||
ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture0"), tex.textures['balloon']['rainbow_mask'].texture)
|
||||
ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture1"), tex.textures['balloon']['rainbow'].texture)
|
||||
self.init_tja(global_data.selected_song, session_data.selected_difficulty)
|
||||
session_data = global_data.session_data[global_data.player_num-1]
|
||||
self.init_tja(global_data.selected_song)
|
||||
self.load_hitsounds()
|
||||
self.song_info = SongInfo(session_data.song_title, session_data.genre_index)
|
||||
self.result_transition = ResultTransition(global_data.player_num)
|
||||
@@ -126,9 +120,10 @@ class GameScreen:
|
||||
"""Write the score to the database"""
|
||||
if self.tja is None:
|
||||
return
|
||||
if global_data.modifiers.auto:
|
||||
if global_data.modifiers[global_data.player_num-1].auto:
|
||||
return
|
||||
with sqlite3.connect('scores.db') as con:
|
||||
session_data = global_data.session_data[global_data.player_num-1]
|
||||
cursor = con.cursor()
|
||||
notes, _, _, _ = TJAParser.notes_to_position(TJAParser(self.tja.file_path), self.player_1.difficulty)
|
||||
hash = self.tja.hash_note_data(notes)
|
||||
@@ -180,7 +175,7 @@ class GameScreen:
|
||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_F1):
|
||||
if self.song_music is not None:
|
||||
audio.stop_music_stream(self.song_music)
|
||||
self.init_tja(global_data.selected_song, session_data.selected_difficulty)
|
||||
self.init_tja(global_data.selected_song)
|
||||
audio.play_sound('restart', 'sound')
|
||||
self.song_started = False
|
||||
|
||||
@@ -190,7 +185,7 @@ class GameScreen:
|
||||
return self.on_screen_end('SONG_SELECT')
|
||||
|
||||
def spawn_ending_anims(self):
|
||||
if session_data.result_bad == 0:
|
||||
if global_data.session_data[global_data.player_num-1].result_bad == 0:
|
||||
self.player_1.ending_anim = FCAnimation(self.player_1.is_2p)
|
||||
elif self.player_1.gauge.is_clear:
|
||||
self.player_1.ending_anim = ClearAnimation(self.player_1.is_2p)
|
||||
@@ -223,6 +218,7 @@ class GameScreen:
|
||||
if self.result_transition.is_finished and not audio.is_sound_playing('result_transition'):
|
||||
return self.on_screen_end('RESULT')
|
||||
elif self.current_ms >= self.player_1.end_time:
|
||||
session_data = global_data.session_data[global_data.player_num-1]
|
||||
session_data.result_score, session_data.result_good, session_data.result_ok, session_data.result_bad, session_data.result_max_combo, session_data.result_total_drumroll = self.player_1.get_result_score()
|
||||
session_data.result_gauge_length = self.player_1.gauge.gauge_length
|
||||
if self.end_ms != 0:
|
||||
@@ -338,7 +334,7 @@ class Player:
|
||||
self.branch_indicator = BranchIndicator(self.is_2p) if tja and tja.metadata.course_data[self.difficulty].is_branching else None
|
||||
self.ending_anim: Optional[FailAnimation | ClearAnimation | FCAnimation] = None
|
||||
self.is_gogo_time = False
|
||||
plate_info = global_data.config['nameplate']
|
||||
plate_info = global_data.config[f'nameplate_{self.is_2p+1}p']
|
||||
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], global_data.player_num, plate_info['dan'], plate_info['gold'])
|
||||
self.chara = Chara2D(player_number - 1, self.bpm)
|
||||
if global_data.config['general']['judge_counter']:
|
||||
@@ -748,7 +744,7 @@ class Player:
|
||||
(is_r_kat_pressed, 'KAT', 'R', f'hitsound_kat_{self.player_number}p')
|
||||
]
|
||||
for check_func, note_type, side, sound in input_checks:
|
||||
if check_func():
|
||||
if check_func(self.player_number):
|
||||
self.lane_hit_effect = LaneHitEffect(note_type, self.is_2p)
|
||||
self.draw_drum_hit_list.append(DrumHitEffect(note_type, side, self.is_2p))
|
||||
|
||||
@@ -994,21 +990,21 @@ class Player:
|
||||
modifiers_to_draw = ['mod_shinuchi']
|
||||
|
||||
# Speed modifiers
|
||||
if global_data.modifiers.speed >= 4:
|
||||
if global_data.modifiers[int(self.player_number)-1].speed >= 4:
|
||||
modifiers_to_draw.append('mod_yonbai')
|
||||
elif global_data.modifiers.speed >= 3:
|
||||
elif global_data.modifiers[int(self.player_number)-1].speed >= 3:
|
||||
modifiers_to_draw.append('mod_sanbai')
|
||||
elif global_data.modifiers.speed > 1:
|
||||
elif global_data.modifiers[int(self.player_number)-1].speed > 1:
|
||||
modifiers_to_draw.append('mod_baisaku')
|
||||
|
||||
# Other modifiers
|
||||
if global_data.modifiers.display:
|
||||
if global_data.modifiers[int(self.player_number)-1].display:
|
||||
modifiers_to_draw.append('mod_doron')
|
||||
if global_data.modifiers.inverse:
|
||||
if global_data.modifiers[int(self.player_number)-1].inverse:
|
||||
modifiers_to_draw.append('mod_abekobe')
|
||||
if global_data.modifiers.random == 2:
|
||||
if global_data.modifiers[int(self.player_number)-1].random == 2:
|
||||
modifiers_to_draw.append('mod_detarame')
|
||||
elif global_data.modifiers.random == 1:
|
||||
elif global_data.modifiers[int(self.player_number)-1].random == 1:
|
||||
modifiers_to_draw.append('mod_kimagure')
|
||||
|
||||
# Draw all modifiers in one batch
|
||||
@@ -1038,8 +1034,6 @@ class Player:
|
||||
# Group 4: Lane covers and UI elements (batch similar textures)
|
||||
tex.draw_texture('lane', f'{self.player_number}p_lane_cover', index=self.is_2p)
|
||||
tex.draw_texture('lane', 'drum', index=self.is_2p)
|
||||
if global_data.modifiers.auto:
|
||||
tex.draw_texture('lane', 'auto_icon', index=self.is_2p)
|
||||
if self.ending_anim is not None:
|
||||
self.ending_anim.draw()
|
||||
|
||||
@@ -1064,11 +1058,13 @@ class Player:
|
||||
self.judge_counter.draw()
|
||||
|
||||
# Group 7: Player-specific elements
|
||||
if not global_data.modifiers.auto:
|
||||
if not self.modifiers.auto:
|
||||
if self.is_2p:
|
||||
self.nameplate.draw(-62, 371)
|
||||
else:
|
||||
self.nameplate.draw(-62, 285)
|
||||
else:
|
||||
tex.draw_texture('lane', 'auto_icon', index=self.is_2p)
|
||||
self.draw_modifiers()
|
||||
self.chara.draw(y=(self.is_2p*536))
|
||||
|
||||
|
||||
@@ -7,18 +7,18 @@ from libs.global_objects import AllNetIcon
|
||||
from libs.song_hash import build_song_hashes
|
||||
from libs.texture import tex
|
||||
from libs.utils import get_current_ms, global_data
|
||||
from scenes.song_select import SongSelectScreen
|
||||
from libs.file_navigator import navigator
|
||||
|
||||
|
||||
class LoadScreen:
|
||||
def __init__(self, song_select_screen: SongSelectScreen):
|
||||
def __init__(self):
|
||||
self.width = 1280
|
||||
self.height = 720
|
||||
self.screen_init = False
|
||||
self.songs_loaded = False
|
||||
self.navigator_started = False
|
||||
self.loading_complete = False
|
||||
self.song_select_screen = song_select_screen
|
||||
self.navigator = navigator
|
||||
|
||||
# Progress bar settings
|
||||
self.progress_bar_width = self.width * 0.43
|
||||
@@ -40,7 +40,7 @@ class LoadScreen:
|
||||
|
||||
def _load_navigator(self):
|
||||
"""Background thread function to load navigator"""
|
||||
self.song_select_screen.load_navigator()
|
||||
self.navigator.initialize(global_data.config["paths"]["tja_path"])
|
||||
self.loading_complete = True
|
||||
|
||||
def on_screen_start(self):
|
||||
|
||||
399
scenes/result.py
399
scenes/result.py
@@ -1,6 +1,6 @@
|
||||
import pyray as ray
|
||||
|
||||
from libs import utils
|
||||
from libs.global_data import reset_session
|
||||
from libs.audio import audio
|
||||
from libs.chara_2d import Chara2D
|
||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate
|
||||
@@ -10,8 +10,7 @@ from libs.utils import (
|
||||
get_current_ms,
|
||||
global_data,
|
||||
is_l_don_pressed,
|
||||
is_r_don_pressed,
|
||||
session_data,
|
||||
is_r_don_pressed
|
||||
)
|
||||
|
||||
|
||||
@@ -34,29 +33,108 @@ class ResultScreen:
|
||||
tex.load_screen_textures('result')
|
||||
audio.load_screen_sounds('result')
|
||||
self.screen_init = True
|
||||
self.song_info = OutlinedText(session_data.song_title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||
self.song_info = OutlinedText(global_data.session_data[0].song_title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||
audio.play_sound('bgm', 'music')
|
||||
self.fade_in = FadeIn()
|
||||
self.fade_in = FadeIn(str(global_data.player_num))
|
||||
self.fade_out = tex.get_animation(0)
|
||||
self.fade_in_bottom = tex.get_animation(1)
|
||||
self.coin_overlay = CoinOverlay()
|
||||
self.allnet_indicator = AllNetIcon()
|
||||
self.start_ms = get_current_ms()
|
||||
self.is_skipped = False
|
||||
self.background = Background(str(global_data.player_num), self.width)
|
||||
self.player_1 = ResultPlayer(str(global_data.player_num), False, False)
|
||||
|
||||
def on_screen_end(self, next_screen: str):
|
||||
self.screen_init = False
|
||||
global_data.songs_played += 1
|
||||
tex.unload_textures()
|
||||
audio.stop_sound('bgm')
|
||||
audio.unload_all_sounds()
|
||||
audio.unload_all_music()
|
||||
reset_session()
|
||||
return next_screen
|
||||
|
||||
def handle_input(self):
|
||||
if is_r_don_pressed() or is_l_don_pressed():
|
||||
if not self.is_skipped:
|
||||
self.is_skipped = True
|
||||
else:
|
||||
self.fade_out.start()
|
||||
audio.play_sound('don', 'sound')
|
||||
|
||||
def update(self):
|
||||
self.on_screen_start()
|
||||
current_time = get_current_ms()
|
||||
self.fade_in.update(current_time)
|
||||
self.player_1.update(current_time, self.fade_in.is_finished, self.is_skipped)
|
||||
|
||||
if current_time >= self.start_ms + 5000 and not self.fade_out.is_started:
|
||||
self.handle_input()
|
||||
|
||||
self.fade_out.update(current_time)
|
||||
if self.fade_out.is_finished:
|
||||
self.fade_out.update(current_time)
|
||||
return self.on_screen_end("SONG_SELECT")
|
||||
|
||||
def draw_overlay(self):
|
||||
self.fade_in.draw()
|
||||
ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.BLACK, self.fade_out.attribute))
|
||||
self.coin_overlay.draw()
|
||||
self.allnet_indicator.draw()
|
||||
|
||||
def draw_song_info(self):
|
||||
tex.draw_texture('song_info', 'song_num', frame=global_data.songs_played%4)
|
||||
dest = ray.Rectangle(1252 - self.song_info.texture.width, 35 - self.song_info.texture.height / 2, self.song_info.texture.width, self.song_info.texture.height)
|
||||
self.song_info.draw(self.song_info.default_src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
|
||||
|
||||
def draw(self):
|
||||
self.background.draw()
|
||||
self.draw_song_info()
|
||||
self.player_1.draw()
|
||||
self.draw_overlay()
|
||||
|
||||
|
||||
class Background:
|
||||
def __init__(self, player_num: str, width: int):
|
||||
self.player_num = player_num
|
||||
self.width = width
|
||||
def draw(self):
|
||||
x = 0
|
||||
if self.player_num == '3':
|
||||
while x < self.width:
|
||||
tex.draw_texture('background', 'background_1p', x=x, y=-360)
|
||||
tex.draw_texture('background', 'background_2p', x=x, y=360)
|
||||
tex.draw_texture('background', 'footer_1p', x=x, y=-72)
|
||||
tex.draw_texture('background', 'footer_2p', x=x, y=648)
|
||||
x += 256
|
||||
else:
|
||||
while x < self.width:
|
||||
tex.draw_texture('background', f'background_{self.player_num}p', x=x, y=-360)
|
||||
tex.draw_texture('background', f'background_{self.player_num}p', x=x, y=360)
|
||||
tex.draw_texture('background', f'footer_{self.player_num}p', x=x, y=-72)
|
||||
tex.draw_texture('background', f'footer_{self.player_num}p', x=x, y=648)
|
||||
x += 256
|
||||
tex.draw_texture('background', 'result_text')
|
||||
|
||||
class ResultPlayer:
|
||||
def __init__(self, player_num: str, has_2p: bool, is_2p: bool):
|
||||
self.player_num = player_num
|
||||
self.has_2p = has_2p
|
||||
self.is_2p = is_2p
|
||||
self.fade_in_finished = False
|
||||
self.fade_in_bottom = tex.get_animation(1, is_copy=True)
|
||||
self.bottom_characters = BottomCharacters()
|
||||
self.gauge = None
|
||||
self.score_delay = None
|
||||
self.bottom_characters = BottomCharacters()
|
||||
self.crown = None
|
||||
self.state = None
|
||||
self.high_score_indicator = None
|
||||
plate_info = global_data.config['nameplate']
|
||||
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], global_data.player_num, plate_info['dan'], plate_info['gold'])
|
||||
self.chara = Chara2D(global_data.player_num - 1, 100)
|
||||
self.chara = Chara2D(int(self.player_num) - 1, 100)
|
||||
session_data = global_data.session_data[int(self.player_num)-1]
|
||||
self.score_animator = ScoreAnimator(session_data.result_score)
|
||||
self.coin_overlay = CoinOverlay()
|
||||
self.allnet_indicator = AllNetIcon()
|
||||
self.score = ''
|
||||
self.good = ''
|
||||
self.ok = ''
|
||||
self.bad = ''
|
||||
self.max_combo = ''
|
||||
self.total_drumroll = ''
|
||||
plate_info = global_data.config[f'nameplate_{self.player_num}p']
|
||||
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], int(self.player_num), plate_info['dan'], plate_info['gold'])
|
||||
self.score, self.good, self.ok, self.bad, self.max_combo, self.total_drumroll= '', '', '', '', '', ''
|
||||
self.update_list = [['score', session_data.result_score],
|
||||
['good', session_data.result_good],
|
||||
['ok', session_data.result_ok],
|
||||
@@ -64,8 +142,6 @@ class ResultScreen:
|
||||
['max_combo', session_data.result_max_combo],
|
||||
['total_drumroll', session_data.result_total_drumroll]]
|
||||
self.update_index = 0
|
||||
self.is_skipped = False
|
||||
self.start_ms = get_current_ms()
|
||||
if session_data.result_ok == 0 and session_data.result_bad == 0:
|
||||
self.crown_type = 'crown_dfc'
|
||||
elif session_data.result_bad == 0:
|
||||
@@ -73,21 +149,11 @@ class ResultScreen:
|
||||
else:
|
||||
self.crown_type = 'crown_clear'
|
||||
|
||||
def on_screen_end(self):
|
||||
self.screen_init = False
|
||||
global_data.songs_played += 1
|
||||
tex.unload_textures()
|
||||
audio.stop_sound('bgm')
|
||||
audio.unload_all_sounds()
|
||||
audio.unload_all_music()
|
||||
utils.session_data = utils.reset_session()
|
||||
return "SONG_SELECT"
|
||||
|
||||
def update_score_animation(self):
|
||||
def update_score_animation(self, is_skipped: bool):
|
||||
"""
|
||||
Update the score animation if a high score is achieved.
|
||||
"""
|
||||
if self.is_skipped:
|
||||
if is_skipped:
|
||||
if self.update_index == len(self.update_list) - 1:
|
||||
return
|
||||
setattr(self, self.update_list[self.update_index][0], self.update_list[self.update_index][1])
|
||||
@@ -109,146 +175,102 @@ class ResultScreen:
|
||||
self.score_animator = ScoreAnimator(self.update_list[self.update_index][1])
|
||||
self.score_delay += 16.67 * 3
|
||||
if self.update_index > 0 and self.high_score_indicator is None:
|
||||
session_data = global_data.session_data[int(self.player_num)-1]
|
||||
if session_data.result_score > session_data.prev_score:
|
||||
self.high_score_indicator = HighScoreIndicator(session_data.prev_score, session_data.result_score)
|
||||
self.high_score_indicator = HighScoreIndicator(session_data.prev_score, session_data.result_score, self.is_2p)
|
||||
|
||||
def handle_input(self):
|
||||
if is_r_don_pressed() or is_l_don_pressed():
|
||||
if not self.is_skipped:
|
||||
self.is_skipped = True
|
||||
else:
|
||||
self.fade_out.start()
|
||||
audio.play_sound('don', 'sound')
|
||||
|
||||
def update(self):
|
||||
self.on_screen_start()
|
||||
current_time = get_current_ms()
|
||||
self.fade_in.update(current_time)
|
||||
if self.fade_in.is_finished and self.gauge is None:
|
||||
self.gauge = Gauge(str(global_data.player_num), session_data.result_gauge_length)
|
||||
def update(self, current_ms: float, fade_in_finished: bool, is_skipped: bool):
|
||||
self.fade_in_finished = fade_in_finished
|
||||
if self.fade_in_finished and self.gauge is None:
|
||||
self.gauge = Gauge(self.player_num, global_data.session_data[int(self.player_num)-1].result_gauge_length, self.is_2p)
|
||||
self.bottom_characters.start()
|
||||
|
||||
self.bottom_characters.update(self.state)
|
||||
self.update_score_animation(is_skipped)
|
||||
|
||||
if self.bottom_characters.is_finished and self.crown is None:
|
||||
if self.gauge is not None and self.gauge.gauge_length > 69:
|
||||
self.crown = Crown()
|
||||
self.crown = Crown(self.is_2p)
|
||||
|
||||
if self.high_score_indicator is not None:
|
||||
self.high_score_indicator.update(current_ms)
|
||||
|
||||
self.fade_in_bottom.update(current_ms)
|
||||
self.nameplate.update(current_ms)
|
||||
if self.gauge is not None:
|
||||
self.gauge.update(current_time)
|
||||
self.gauge.update(current_ms)
|
||||
if self.gauge.is_finished and self.score_delay is None:
|
||||
self.score_delay = current_time + 1883
|
||||
self.score_delay = current_ms + 1883
|
||||
|
||||
if self.score_delay is not None:
|
||||
if current_time > self.score_delay and not self.fade_in_bottom.is_started:
|
||||
if current_ms > self.score_delay and not self.fade_in_bottom.is_started:
|
||||
self.fade_in_bottom.start()
|
||||
if self.gauge is not None:
|
||||
self.state = self.gauge.state
|
||||
|
||||
if self.high_score_indicator is not None:
|
||||
self.high_score_indicator.update(current_time)
|
||||
|
||||
self.fade_in_bottom.update(current_time)
|
||||
|
||||
if current_time >= self.start_ms + 5000 and not self.fade_out.is_started:
|
||||
self.handle_input()
|
||||
|
||||
self.update_score_animation()
|
||||
|
||||
self.fade_out.update(current_time)
|
||||
if self.fade_out.is_finished:
|
||||
self.fade_out.update(current_time)
|
||||
return self.on_screen_end()
|
||||
|
||||
if self.crown is not None:
|
||||
self.crown.update(current_time)
|
||||
self.crown.update(current_ms)
|
||||
|
||||
self.nameplate.update(current_time)
|
||||
self.chara.update(current_time, 100, False, False)
|
||||
self.chara.update(current_ms, 100, False, False)
|
||||
|
||||
def draw_score_info(self):
|
||||
"""
|
||||
Draw the score information.
|
||||
"""
|
||||
if self.good != '':
|
||||
for i in range(len(str(self.good))):
|
||||
tex.draw_texture('score', 'judge_num', frame=int(str(self.good)[::-1][i]), x=943-(i*24), y=186)
|
||||
if self.ok != '':
|
||||
for i in range(len(str(self.ok))):
|
||||
tex.draw_texture('score', 'judge_num', frame=int(str(self.ok)[::-1][i]), x=943-(i*24), y=227)
|
||||
if self.bad != '':
|
||||
for i in range(len(str(self.bad))):
|
||||
tex.draw_texture('score', 'judge_num', frame=int(str(self.bad)[::-1][i]), x=943-(i*24), y=267)
|
||||
if self.max_combo != '':
|
||||
for i in range(len(str(self.max_combo))):
|
||||
tex.draw_texture('score', 'judge_num', frame=int(str(self.max_combo)[::-1][i]), x=1217-(i*24), y=186)
|
||||
if self.total_drumroll != '':
|
||||
for i in range(len(str(self.total_drumroll))):
|
||||
tex.draw_texture('score', 'judge_num', frame=int(str(self.total_drumroll)[::-1][i]), x=1217-(i*24), y=227)
|
||||
"""Draw the score information."""
|
||||
for j, score in enumerate([self.good, self.ok, self.bad, self.max_combo, self.total_drumroll]):
|
||||
if score == '':
|
||||
continue
|
||||
score_str = str(score)[::-1]
|
||||
for i, digit in enumerate(score_str):
|
||||
tex.draw_texture('score', 'judge_num', frame=int(digit), x=-(i*24), index=j+(self.is_2p*5))
|
||||
|
||||
def draw_total_score(self):
|
||||
"""
|
||||
Draw the total score.
|
||||
"""
|
||||
if not self.fade_in.is_finished:
|
||||
if not self.fade_in_finished:
|
||||
return
|
||||
tex.draw_texture('score', 'score_shinuchi')
|
||||
tex.draw_texture('score', 'score_shinuchi', index=self.is_2p)
|
||||
if self.score != '':
|
||||
for i in range(len(str(self.score))):
|
||||
tex.draw_texture('score', 'score_num', x=-(i*21), frame=int(str(self.score)[::-1][i]))
|
||||
|
||||
def draw_bottom_textures(self):
|
||||
"""Draw the bottom textures."""
|
||||
if self.state == State.FAIL:
|
||||
tex.draw_texture('background', 'gradient_fail', fade=min(0.4, self.fade_in_bottom.attribute))
|
||||
else:
|
||||
tex.draw_texture('background', 'gradient_clear', fade=min(0.4, self.fade_in_bottom.attribute))
|
||||
self.bottom_characters.draw()
|
||||
tex.draw_texture('score', 'score_num', x=-(i*21), frame=int(str(self.score)[::-1][i]), index=self.is_2p)
|
||||
|
||||
def draw_modifiers(self):
|
||||
"""Draw the modifiers if enabled."""
|
||||
if global_data.modifiers.display:
|
||||
tex.draw_texture('score', 'mod_doron')
|
||||
if global_data.modifiers.inverse:
|
||||
tex.draw_texture('score', 'mod_abekobe')
|
||||
if global_data.modifiers.random == 1:
|
||||
tex.draw_texture('score', 'mod_kimagure')
|
||||
elif global_data.modifiers.random == 2:
|
||||
tex.draw_texture('score', 'mod_detarame')
|
||||
if global_data.modifiers.speed >= 4:
|
||||
tex.draw_texture('score', 'mod_yonbai')
|
||||
elif global_data.modifiers.speed >= 3:
|
||||
tex.draw_texture('score', 'mod_sanbai')
|
||||
elif global_data.modifiers.speed > 1:
|
||||
tex.draw_texture('score', 'mod_baisaku')
|
||||
if global_data.modifiers[int(self.player_num)-1].display:
|
||||
tex.draw_texture('score', 'mod_doron', index=self.is_2p)
|
||||
if global_data.modifiers[int(self.player_num)-1].inverse:
|
||||
tex.draw_texture('score', 'mod_abekobe', index=self.is_2p)
|
||||
if global_data.modifiers[int(self.player_num)-1].random == 1:
|
||||
tex.draw_texture('score', 'mod_kimagure', index=self.is_2p)
|
||||
elif global_data.modifiers[int(self.player_num)-1].random == 2:
|
||||
tex.draw_texture('score', 'mod_detarame', index=self.is_2p)
|
||||
if global_data.modifiers[int(self.player_num)-1].speed >= 4:
|
||||
tex.draw_texture('score', 'mod_yonbai', index=self.is_2p)
|
||||
elif global_data.modifiers[int(self.player_num)-1].speed >= 3:
|
||||
tex.draw_texture('score', 'mod_sanbai', index=self.is_2p)
|
||||
elif global_data.modifiers[int(self.player_num)-1].speed > 1:
|
||||
tex.draw_texture('score', 'mod_baisaku', index=self.is_2p)
|
||||
|
||||
def draw(self):
|
||||
x = 0
|
||||
while x < self.width:
|
||||
tex.draw_texture('background', f'background_{str(global_data.player_num)}p', x=x, y=-360)
|
||||
tex.draw_texture('background', f'background_{str(global_data.player_num)}p', x=x, y=360)
|
||||
tex.draw_texture('background', f'footer_{str(global_data.player_num)}p', x=x, y=-72)
|
||||
tex.draw_texture('background', f'footer_{str(global_data.player_num)}p', x=x, y=648)
|
||||
x += 256
|
||||
if self.is_2p:
|
||||
if self.state == State.FAIL:
|
||||
tex.draw_texture('background', 'gradient_fail', fade=min(0.4, self.fade_in_bottom.attribute))
|
||||
elif self.state == State.CLEAR:
|
||||
tex.draw_texture('background', 'gradient_clear', fade=min(0.4, self.fade_in_bottom.attribute))
|
||||
else:
|
||||
y = -288 if self.has_2p else 0
|
||||
if self.state == State.FAIL:
|
||||
tex.draw_texture('background', 'gradient_fail', fade=min(0.4, self.fade_in_bottom.attribute), y=y)
|
||||
elif self.state == State.CLEAR:
|
||||
tex.draw_texture('background', 'gradient_clear', fade=min(0.4, self.fade_in_bottom.attribute), y=y)
|
||||
tex.draw_texture('score', 'overlay', color=ray.fade(ray.WHITE, 0.75), index=self.is_2p)
|
||||
tex.draw_texture('score', 'difficulty', frame=global_data.session_data[int(self.player_num)-1].selected_difficulty, index=self.is_2p)
|
||||
if not self.has_2p:
|
||||
self.bottom_characters.draw()
|
||||
|
||||
tex.draw_texture('background', 'result_text')
|
||||
tex.draw_texture('song_info', 'song_num', frame=global_data.songs_played%4)
|
||||
dest = ray.Rectangle(1252 - self.song_info.texture.width, 35 - self.song_info.texture.height / 2, self.song_info.texture.width, self.song_info.texture.height)
|
||||
self.song_info.draw(self.song_info.default_src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
|
||||
|
||||
tex.draw_texture('score', 'overlay', color=ray.fade(ray.WHITE, 0.75))
|
||||
tex.draw_texture('score', 'difficulty', frame=session_data.selected_difficulty)
|
||||
|
||||
self.draw_bottom_textures()
|
||||
|
||||
if self.gauge is not None:
|
||||
self.gauge.draw()
|
||||
|
||||
tex.draw_texture('score', 'judge_good')
|
||||
tex.draw_texture('score', 'judge_ok')
|
||||
tex.draw_texture('score', 'judge_bad')
|
||||
tex.draw_texture('score', 'max_combo')
|
||||
tex.draw_texture('score', 'drumroll')
|
||||
tex.draw_texture('score', 'judge_good', index=self.is_2p)
|
||||
tex.draw_texture('score', 'judge_ok', index=self.is_2p)
|
||||
tex.draw_texture('score', 'judge_bad', index=self.is_2p)
|
||||
tex.draw_texture('score', 'max_combo', index=self.is_2p)
|
||||
tex.draw_texture('score', 'drumroll', index=self.is_2p)
|
||||
|
||||
self.draw_score_info()
|
||||
self.draw_total_score()
|
||||
@@ -256,31 +278,25 @@ class ResultScreen:
|
||||
if self.crown is not None:
|
||||
self.crown.draw(self.crown_type)
|
||||
|
||||
self.nameplate.draw(265, 80)
|
||||
|
||||
self.draw_modifiers()
|
||||
|
||||
if self.high_score_indicator is not None:
|
||||
self.high_score_indicator.draw()
|
||||
|
||||
self.chara.draw(y=100)
|
||||
|
||||
self.fade_in.draw()
|
||||
ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.BLACK, self.fade_out.attribute))
|
||||
self.coin_overlay.draw()
|
||||
self.allnet_indicator.draw()
|
||||
|
||||
def draw_3d(self):
|
||||
pass
|
||||
self.chara.draw(y=100+(self.is_2p*360))
|
||||
if self.gauge is not None:
|
||||
self.gauge.draw()
|
||||
self.nameplate.draw(265, 80+(self.is_2p*300))
|
||||
|
||||
class Crown:
|
||||
"""Represents a crown animation"""
|
||||
def __init__(self):
|
||||
self.resize = tex.get_animation(2)
|
||||
self.resize_fix = tex.get_animation(3)
|
||||
self.white_fadein = tex.get_animation(4)
|
||||
self.gleam = tex.get_animation(5)
|
||||
self.fadein = tex.get_animation(6)
|
||||
def __init__(self, is_2p: bool):
|
||||
self.is_2p = is_2p
|
||||
self.resize = tex.get_animation(2, is_copy=True)
|
||||
self.resize_fix = tex.get_animation(3, is_copy=True)
|
||||
self.white_fadein = tex.get_animation(4, is_copy=True)
|
||||
self.gleam = tex.get_animation(5, is_copy=True)
|
||||
self.fadein = tex.get_animation(6, is_copy=True)
|
||||
self.resize.start()
|
||||
self.resize_fix.start()
|
||||
self.white_fadein.start()
|
||||
@@ -302,10 +318,10 @@ class Crown:
|
||||
scale = self.resize.attribute
|
||||
if self.resize.is_finished:
|
||||
scale = self.resize_fix.attribute
|
||||
tex.draw_texture('crown', crown_name, scale=scale, center=True)
|
||||
tex.draw_texture('crown', 'crown_fade', fade=self.white_fadein.attribute)
|
||||
tex.draw_texture('crown', crown_name, scale=scale, center=True, index=self.is_2p)
|
||||
tex.draw_texture('crown', 'crown_fade', fade=self.white_fadein.attribute, index=self.is_2p)
|
||||
if self.gleam.attribute >= 0:
|
||||
tex.draw_texture('crown', 'gleam', frame=self.gleam.attribute)
|
||||
tex.draw_texture('crown', 'gleam', frame=self.gleam.attribute, index=self.is_2p)
|
||||
|
||||
class BottomCharacters:
|
||||
"""Represents the bottom characters animation"""
|
||||
@@ -387,10 +403,11 @@ class BottomCharacters:
|
||||
|
||||
class FadeIn:
|
||||
"""A fade out disguised as a fade in"""
|
||||
def __init__(self):
|
||||
def __init__(self, player_num: str):
|
||||
self.fadein = tex.get_animation(15)
|
||||
self.fadein.start()
|
||||
self.is_finished = False
|
||||
self.player_num = player_num
|
||||
|
||||
def update(self, current_ms: float):
|
||||
self.fadein.update(current_ms)
|
||||
@@ -398,11 +415,19 @@ class FadeIn:
|
||||
|
||||
def draw(self):
|
||||
x = 0
|
||||
if self.player_num == '3':
|
||||
while x < 1280:
|
||||
tex.draw_texture('background', f'background_{str(global_data.player_num)}p', x=x, y=-360, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', f'background_{str(global_data.player_num)}p', x=x, y=360, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', f'footer_{str(global_data.player_num)}p', x=x, y=-72, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', f'footer_{str(global_data.player_num)}p', x=x, y=648, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', 'background_1p', x=x, y=-360, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', 'background_2p', x=x, y=360, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', 'footer_1p', x=x, y=-72, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', 'footer_2p', x=x, y=648, fade=self.fadein.attribute)
|
||||
x += 256
|
||||
else:
|
||||
while x < 1280:
|
||||
tex.draw_texture('background', f'background_{self.player_num}p', x=x, y=-360, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', f'background_{self.player_num}p', x=x, y=360, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', f'footer_{self.player_num}p', x=x, y=-72, fade=self.fadein.attribute)
|
||||
tex.draw_texture('background', f'footer_{self.player_num}p', x=x, y=648, fade=self.fadein.attribute)
|
||||
x += 256
|
||||
|
||||
class ScoreAnimator:
|
||||
@@ -434,7 +459,8 @@ class ScoreAnimator:
|
||||
|
||||
class HighScoreIndicator:
|
||||
"""Indicates the difference between the old and new high score"""
|
||||
def __init__(self, old_score: int, new_score: int):
|
||||
def __init__(self, old_score: int, new_score: int, is_2p: bool):
|
||||
self.is_2p = is_2p
|
||||
self.score_diff = new_score - old_score
|
||||
self.move = tex.get_animation(18)
|
||||
self.fade = tex.get_animation(19)
|
||||
@@ -446,16 +472,17 @@ class HighScoreIndicator:
|
||||
self.fade.update(current_ms)
|
||||
|
||||
def draw(self):
|
||||
tex.draw_texture('score', 'high_score', y=self.move.attribute, fade=self.fade.attribute)
|
||||
tex.draw_texture('score', 'high_score', y=self.move.attribute, fade=self.fade.attribute, index=self.is_2p)
|
||||
for i in range(len(str(self.score_diff))):
|
||||
tex.draw_texture('score', 'high_score_num', x=-(i*14), frame=int(str(self.score_diff)[::-1][i]), y=self.move.attribute, fade=self.fade.attribute)
|
||||
tex.draw_texture('score', 'high_score_num', x=-(i*14), frame=int(str(self.score_diff)[::-1][i]), y=self.move.attribute, fade=self.fade.attribute, index=self.is_2p)
|
||||
|
||||
|
||||
class Gauge:
|
||||
"""The gauge from the game screen, at 0.9x scale"""
|
||||
def __init__(self, player_num: str, gauge_length: int):
|
||||
def __init__(self, player_num: str, gauge_length: int, is_2p: bool):
|
||||
self.is_2p = is_2p
|
||||
self.player_num = player_num
|
||||
self.difficulty = min(2, session_data.selected_difficulty)
|
||||
self.difficulty = min(2, global_data.session_data[int(player_num)-1].selected_difficulty)
|
||||
self.gauge_length = gauge_length
|
||||
self.clear_start = [69, 69, 69]
|
||||
self.gauge_max = 87
|
||||
@@ -488,37 +515,37 @@ class Gauge:
|
||||
|
||||
def draw(self):
|
||||
scale = 10/11
|
||||
tex.draw_texture('gauge', f'{self.player_num}p_unfilled' + self.string_diff, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', f'{self.player_num}p_unfilled' + self.string_diff, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
gauge_length = int(self.gauge_length)
|
||||
if gauge_length == self.gauge_max:
|
||||
if 0 < self.rainbow_animation.attribute < 8:
|
||||
tex.draw_texture('gauge', 'rainbow' + self.string_diff, frame=self.rainbow_animation.attribute-1, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'rainbow' + self.string_diff, frame=self.rainbow_animation.attribute, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'rainbow' + self.string_diff, frame=self.rainbow_animation.attribute-1, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
tex.draw_texture('gauge', 'rainbow' + self.string_diff, frame=self.rainbow_animation.attribute, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
else:
|
||||
for i in range(gauge_length+1):
|
||||
width = int(i * 7.2)
|
||||
if i == self.clear_start[self.difficulty] - 1:
|
||||
tex.draw_texture('gauge', 'bar_clear_transition', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'bar_clear_transition', x=width, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
elif i > self.clear_start[self.difficulty] - 1:
|
||||
if i % 5 == 0:
|
||||
tex.draw_texture('gauge', 'bar_clear_top', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'bar_clear_bottom', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'bar_clear_top', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'bar_clear_bottom', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'bar_clear_top', x=width, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
tex.draw_texture('gauge', 'bar_clear_bottom', x=width, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
tex.draw_texture('gauge', 'bar_clear_top', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
tex.draw_texture('gauge', 'bar_clear_bottom', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
else:
|
||||
if i % 5 == 0:
|
||||
tex.draw_texture('gauge', f'{self.player_num}p_bar', x=width, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', f'{self.player_num}p_bar', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'overlay' + self.string_diff, scale=scale, fade=min(0.15, self.gauge_fade_in.attribute))
|
||||
tex.draw_texture('gauge', 'footer', scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', f'{self.player_num}p_bar', x=width, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
tex.draw_texture('gauge', f'{self.player_num}p_bar', x=width+1, scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
tex.draw_texture('gauge', 'overlay' + self.string_diff, scale=scale, fade=min(0.15, self.gauge_fade_in.attribute), index=self.is_2p)
|
||||
tex.draw_texture('gauge', 'footer', scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
|
||||
if gauge_length >= self.clear_start[self.difficulty]:
|
||||
tex.draw_texture('gauge', 'clear', scale=scale, fade=self.gauge_fade_in.attribute, index=self.difficulty)
|
||||
tex.draw_texture('gauge', 'clear', scale=scale, fade=self.gauge_fade_in.attribute, index=self.difficulty+(self.is_2p*3))
|
||||
if self.state == State.RAINBOW:
|
||||
tex.draw_texture('gauge', 'tamashii_fire', scale=0.75 * scale, center=True, frame=self.tamashii_fire_change.attribute, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'tamashii', scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'tamashii_fire', scale=0.75 * scale, center=True, frame=self.tamashii_fire_change.attribute, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
tex.draw_texture('gauge', 'tamashii', scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
if self.state == State.RAINBOW and self.tamashii_fire_change.attribute in (0, 1, 4, 5):
|
||||
tex.draw_texture('gauge', 'tamashii_overlay', scale=scale, fade=min(0.5, self.gauge_fade_in.attribute))
|
||||
tex.draw_texture('gauge', 'tamashii_overlay', scale=scale, fade=min(0.5, self.gauge_fade_in.attribute), index=self.is_2p)
|
||||
else:
|
||||
tex.draw_texture('gauge', 'clear_dark', scale=scale, fade=self.gauge_fade_in.attribute, index=self.difficulty)
|
||||
tex.draw_texture('gauge', 'tamashii_dark', scale=scale, fade=self.gauge_fade_in.attribute)
|
||||
tex.draw_texture('gauge', 'clear_dark', scale=scale, fade=self.gauge_fade_in.attribute, index=self.difficulty+(self.is_2p*3))
|
||||
tex.draw_texture('gauge', 'tamashii_dark', scale=scale, fade=self.gauge_fade_in.attribute, index=self.is_2p)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
||||
import copy
|
||||
from pathlib import Path
|
||||
from libs.global_data import Modifiers
|
||||
from libs.tja import TJAParser
|
||||
from libs.utils import get_current_ms
|
||||
from libs.audio import audio
|
||||
from libs.utils import global_data, session_data
|
||||
from libs.utils import global_data
|
||||
from libs.video import VideoPlayer
|
||||
from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, Player, Background, SCREEN_WIDTH
|
||||
import pyray as ray
|
||||
from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, Player, Background, SCREEN_WIDTH, ResultTransition
|
||||
|
||||
class TwoPlayerGameScreen(GameScreen):
|
||||
def on_screen_start(self):
|
||||
@@ -16,27 +16,52 @@ class TwoPlayerGameScreen(GameScreen):
|
||||
if self.background is not None:
|
||||
self.background.unload()
|
||||
self.background = Background(3, self.bpm, scene_preset=scene_preset)
|
||||
self.result_transition = ResultTransition(3)
|
||||
|
||||
def load_hitsounds(self):
|
||||
"""Load the hit sounds"""
|
||||
sounds_dir = Path("Sounds")
|
||||
if global_data.hit_sound == -1:
|
||||
|
||||
# Load hitsounds for 1P
|
||||
if global_data.hit_sound[0] == -1:
|
||||
audio.load_sound(Path('none.wav'), 'hitsound_don_1p')
|
||||
audio.load_sound(Path('none.wav'), 'hitsound_kat_1p')
|
||||
if global_data.hit_sound == 0:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.wav", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.wav", 'hitsound_kat_1p')
|
||||
elif global_data.hit_sound[0] == 0:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.wav", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.wav", 'hitsound_kat_1p')
|
||||
else:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.ogg", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.ogg", 'hitsound_kat_1p')
|
||||
audio.set_sound_pan('hitsound_don_1p', 1.0)
|
||||
audio.set_sound_pan('hitsound_kat_1p', 1.0)
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don_2p.wav", 'hitsound_don_2p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka_2p.wav", 'hitsound_kat_2p')
|
||||
|
||||
# Load hitsounds for 2P
|
||||
if global_data.hit_sound[1] == -1:
|
||||
audio.load_sound(Path('none.wav'), 'hitsound_don_2p')
|
||||
audio.load_sound(Path('none.wav'), 'hitsound_kat_2p')
|
||||
elif global_data.hit_sound[1] == 0:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don_2p.wav", 'hitsound_don_2p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka_2p.wav", 'hitsound_kat_2p')
|
||||
else:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don.ogg", 'hitsound_don_2p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka.ogg", 'hitsound_kat_2p')
|
||||
audio.set_sound_pan('hitsound_don_2p', 0.0)
|
||||
audio.set_sound_pan('hitsound_kat_2p', 0.0)
|
||||
else:
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.ogg", 'hitsound_don_1p')
|
||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.ogg", 'hitsound_kat_1p')
|
||||
|
||||
def init_tja(self, song: Path, difficulty: int):
|
||||
def global_keys(self):
|
||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_F1):
|
||||
if self.song_music is not None:
|
||||
audio.stop_music_stream(self.song_music)
|
||||
self.init_tja(global_data.selected_song)
|
||||
audio.play_sound('restart', 'sound')
|
||||
self.song_started = False
|
||||
|
||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
||||
if self.song_music is not None:
|
||||
audio.stop_music_stream(self.song_music)
|
||||
return self.on_screen_end('SONG_SELECT_2P')
|
||||
|
||||
def init_tja(self, song: Path):
|
||||
"""Initialize the TJA file"""
|
||||
self.tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X)
|
||||
if self.tja.metadata.bgmovie != Path() and self.tja.metadata.bgmovie.exists():
|
||||
@@ -44,24 +69,28 @@ class TwoPlayerGameScreen(GameScreen):
|
||||
self.movie.set_volume(0.0)
|
||||
else:
|
||||
self.movie = None
|
||||
session_data.song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
|
||||
global_data.session_data[0].song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
|
||||
if self.tja.metadata.wave.exists() and self.tja.metadata.wave.is_file() and self.song_music is None:
|
||||
self.song_music = audio.load_music_stream(self.tja.metadata.wave, 'song')
|
||||
|
||||
tja_copy = copy.deepcopy(self.tja)
|
||||
self.player_1 = Player(self.tja, 1, difficulty, False, global_data.modifiers)
|
||||
self.player_2 = Player(tja_copy, 2, difficulty-1, True, Modifiers())
|
||||
self.player_1 = Player(self.tja, 1, global_data.session_data[0].selected_difficulty, False, global_data.modifiers[0])
|
||||
self.player_2 = Player(tja_copy, 2, global_data.session_data[1].selected_difficulty, True, global_data.modifiers[1])
|
||||
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
|
||||
|
||||
def spawn_ending_anims(self):
|
||||
if session_data.result_bad == 0:
|
||||
if global_data.session_data[0].result_bad == 0:
|
||||
self.player_1.ending_anim = FCAnimation(self.player_1.is_2p)
|
||||
self.player_2.ending_anim = FCAnimation(self.player_2.is_2p)
|
||||
elif self.player_1.gauge.is_clear:
|
||||
self.player_1.ending_anim = ClearAnimation(self.player_1.is_2p)
|
||||
self.player_2.ending_anim = ClearAnimation(self.player_2.is_2p)
|
||||
elif not self.player_1.gauge.is_clear:
|
||||
self.player_1.ending_anim = FailAnimation(self.player_1.is_2p)
|
||||
|
||||
if global_data.session_data[1].result_bad == 0:
|
||||
self.player_2.ending_anim = FCAnimation(self.player_2.is_2p)
|
||||
elif self.player_2.gauge.is_clear:
|
||||
self.player_2.ending_anim = ClearAnimation(self.player_2.is_2p)
|
||||
elif not self.player_2.gauge.is_clear:
|
||||
self.player_2.ending_anim = FailAnimation(self.player_2.is_2p)
|
||||
|
||||
def update(self):
|
||||
@@ -80,10 +109,14 @@ class TwoPlayerGameScreen(GameScreen):
|
||||
self.song_info.update(current_time)
|
||||
self.result_transition.update(current_time)
|
||||
if self.result_transition.is_finished and not audio.is_sound_playing('result_transition'):
|
||||
return self.on_screen_end('RESULT')
|
||||
return self.on_screen_end('RESULT_2P')
|
||||
elif self.current_ms >= self.player_1.end_time:
|
||||
session_data = global_data.session_data[0]
|
||||
session_data.result_score, session_data.result_good, session_data.result_ok, session_data.result_bad, session_data.result_max_combo, session_data.result_total_drumroll = self.player_1.get_result_score()
|
||||
session_data.result_gauge_length = self.player_1.gauge.gauge_length
|
||||
session_data = global_data.session_data[1]
|
||||
session_data.result_score, session_data.result_good, session_data.result_ok, session_data.result_bad, session_data.result_max_combo, session_data.result_total_drumroll = self.player_2.get_result_score()
|
||||
session_data.result_gauge_length = self.player_2.gauge.gauge_length
|
||||
if self.end_ms != 0:
|
||||
if current_time >= self.end_ms + 1000:
|
||||
if self.player_1.ending_anim is None:
|
||||
|
||||
36
scenes/two_player/result.py
Normal file
36
scenes/two_player/result.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from libs.utils import get_current_ms
|
||||
from scenes.result import Background, FadeIn, ResultPlayer, ResultScreen
|
||||
|
||||
class TwoPlayerResultScreen(ResultScreen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def on_screen_start(self):
|
||||
if not self.screen_init:
|
||||
super().on_screen_start()
|
||||
self.background = Background('3', self.width)
|
||||
self.fade_in = FadeIn('3')
|
||||
self.player_1 = ResultPlayer('1', True, False)
|
||||
self.player_2 = ResultPlayer('2', True, True)
|
||||
|
||||
def update(self):
|
||||
self.on_screen_start()
|
||||
current_time = get_current_ms()
|
||||
self.fade_in.update(current_time)
|
||||
self.player_1.update(current_time, self.fade_in.is_finished, self.is_skipped)
|
||||
self.player_2.update(current_time, self.fade_in.is_finished, self.is_skipped)
|
||||
|
||||
if current_time >= self.start_ms + 5000 and not self.fade_out.is_started:
|
||||
self.handle_input()
|
||||
|
||||
self.fade_out.update(current_time)
|
||||
if self.fade_out.is_finished:
|
||||
self.fade_out.update(current_time)
|
||||
return self.on_screen_end("SONG_SELECT_2P")
|
||||
|
||||
def draw(self):
|
||||
self.background.draw()
|
||||
self.draw_song_info()
|
||||
self.player_1.draw()
|
||||
self.player_2.draw()
|
||||
self.draw_overlay()
|
||||
166
scenes/two_player/song_select.py
Normal file
166
scenes/two_player/song_select.py
Normal file
@@ -0,0 +1,166 @@
|
||||
from libs.file_navigator import SongFile
|
||||
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.audio import audio
|
||||
|
||||
class TwoPlayerSongSelectScreen(SongSelectScreen):
|
||||
def on_screen_start(self):
|
||||
if not self.screen_init:
|
||||
super().on_screen_start()
|
||||
self.player_1 = SongSelectPlayer('1', self.text_fade_in)
|
||||
self.player_2 = SongSelectPlayer('2', self.text_fade_in)
|
||||
|
||||
def finalize_song(self):
|
||||
global_data.selected_song = self.navigator.get_current_item().path
|
||||
global_data.session_data[0].genre_index = self.navigator.get_current_item().box.name_texture_index
|
||||
|
||||
def handle_input_browsing(self):
|
||||
"""Handle input for browsing songs."""
|
||||
action = self.player_1.handle_input_browsing(self.last_moved, self.navigator.items[self.navigator.selected_index] if self.navigator.items else None)
|
||||
if action is None:
|
||||
action = self.player_2.handle_input_browsing(self.last_moved, self.navigator.items[self.navigator.selected_index] if self.navigator.items else None)
|
||||
if action is None:
|
||||
return
|
||||
|
||||
current_time = get_current_ms()
|
||||
if action == "skip_left":
|
||||
self.reset_demo_music()
|
||||
for _ in range(10):
|
||||
self.navigator.navigate_left()
|
||||
self.last_moved = current_time
|
||||
elif action == "skip_right":
|
||||
self.reset_demo_music()
|
||||
for _ in range(10):
|
||||
self.navigator.navigate_right()
|
||||
self.last_moved = current_time
|
||||
elif action == "navigate_left":
|
||||
self.reset_demo_music()
|
||||
self.navigator.navigate_left()
|
||||
self.last_moved = current_time
|
||||
elif action == "navigate_right":
|
||||
self.reset_demo_music()
|
||||
self.navigator.navigate_right()
|
||||
self.last_moved = current_time
|
||||
elif action == "go_back":
|
||||
self.navigator.go_back()
|
||||
elif action == "diff_sort":
|
||||
self.state = State.DIFF_SORTING
|
||||
self.diff_sort_selector = DiffSortSelect(self.navigator.diff_sort_statistics, self.navigator.diff_sort_diff, self.navigator.diff_sort_level)
|
||||
self.text_fade_in.start()
|
||||
self.text_fade_out.start()
|
||||
elif action == "select_song":
|
||||
selected_song = self.navigator.select_current_item()
|
||||
if selected_song:
|
||||
self.state = State.SONG_SELECTED
|
||||
self.player_1.on_song_selected(selected_song)
|
||||
audio.play_sound('don', 'sound')
|
||||
audio.play_sound('voice_select_diff', 'voice')
|
||||
self.move_away.start()
|
||||
self.diff_fade_out.start()
|
||||
self.text_fade_out.start()
|
||||
self.text_fade_in.start()
|
||||
self.player_1.selected_diff_bounce.start()
|
||||
self.player_1.selected_diff_fadein.start()
|
||||
self.player_2.selected_diff_bounce.start()
|
||||
self.player_2.selected_diff_fadein.start()
|
||||
elif action == "add_favorite":
|
||||
self.navigator.add_favorite()
|
||||
current_box = self.navigator.get_current_item().box
|
||||
current_box.is_favorite = not current_box.is_favorite
|
||||
|
||||
def handle_input_selected(self):
|
||||
"""Handle input for selecting difficulty."""
|
||||
p2_result = False
|
||||
result = self.player_1.handle_input_selected(self.navigator.get_current_item())
|
||||
if result is None:
|
||||
result = self.player_2.handle_input_selected(self.navigator.get_current_item())
|
||||
if result is None:
|
||||
return
|
||||
p2_result = True
|
||||
if result is not None:
|
||||
print(result, p2_result)
|
||||
if result == "cancel":
|
||||
self._cancel_selection()
|
||||
elif result == "confirm":
|
||||
if p2_result:
|
||||
self._confirm_selection(2)
|
||||
else:
|
||||
self._confirm_selection(1)
|
||||
elif result == "ura_toggle":
|
||||
if p2_result:
|
||||
self.ura_switch_animation.start(not self.player_2.is_ura)
|
||||
else:
|
||||
self.ura_switch_animation.start(not self.player_1.is_ura)
|
||||
|
||||
def handle_input_diff_sort(self):
|
||||
"""
|
||||
Handle input for sorting difficulty.
|
||||
"""
|
||||
if self.diff_sort_selector is None:
|
||||
raise Exception("Diff sort selector was not able to be created")
|
||||
|
||||
result = self.player_1.handle_input_diff_sort(self.diff_sort_selector)
|
||||
|
||||
if result is not None:
|
||||
diff, level = result
|
||||
self.diff_sort_selector = None
|
||||
self.state = State.BROWSING
|
||||
self.text_fade_out.reset()
|
||||
self.text_fade_in.reset()
|
||||
if diff != -1:
|
||||
if level != -1:
|
||||
self.navigator.diff_sort_diff = diff
|
||||
self.navigator.diff_sort_level = level
|
||||
self.navigator.select_current_item()
|
||||
|
||||
def _cancel_selection(self):
|
||||
"""Reset to browsing state"""
|
||||
super()._cancel_selection()
|
||||
self.player_2.selected_song = None
|
||||
|
||||
def _confirm_selection(self, player_selected: int):
|
||||
"""Confirm song selection and create game transition"""
|
||||
audio.play_sound('don', 'sound')
|
||||
audio.play_sound(f'voice_start_song_{global_data.player_num}p', 'voice')
|
||||
if player_selected == 1:
|
||||
global_data.session_data[0].selected_difficulty = self.player_1.selected_difficulty
|
||||
self.player_1.selected_diff_highlight_fade.start()
|
||||
self.player_1.selected_diff_text_resize.start()
|
||||
self.player_1.selected_diff_text_fadein.start()
|
||||
elif player_selected == 2:
|
||||
global_data.session_data[1].selected_difficulty = self.player_2.selected_difficulty
|
||||
self.player_2.selected_diff_highlight_fade.start()
|
||||
self.player_2.selected_diff_text_resize.start()
|
||||
self.player_2.selected_diff_text_fadein.start()
|
||||
|
||||
def check_for_selection(self):
|
||||
if (self.player_1.selected_diff_highlight_fade.is_finished and
|
||||
self.player_2.selected_diff_highlight_fade.is_finished and
|
||||
not audio.is_sound_playing(f'voice_start_song_{global_data.player_num}p') and self.game_transition is None):
|
||||
selected_song = self.navigator.get_current_item()
|
||||
if not isinstance(selected_song, SongFile):
|
||||
raise Exception("picked directory")
|
||||
|
||||
title = selected_song.tja.metadata.title.get(
|
||||
global_data.config['general']['language'], '')
|
||||
subtitle = selected_song.tja.metadata.subtitle.get(
|
||||
global_data.config['general']['language'], '')
|
||||
self.game_transition = Transition(title, subtitle)
|
||||
self.game_transition.start()
|
||||
|
||||
def update_players(self, current_time):
|
||||
self.player_1.update(current_time)
|
||||
self.player_2.update(current_time)
|
||||
if self.text_fade_out.is_finished:
|
||||
self.player_1.selected_song = True
|
||||
self.player_2.selected_song = True
|
||||
return "GAME_2P"
|
||||
|
||||
def draw_background_diffs(self):
|
||||
self.player_1.draw_background_diffs(self.state)
|
||||
self.player_2.draw_background_diffs(self.state)
|
||||
|
||||
def draw_players(self):
|
||||
self.player_1.draw(self.state)
|
||||
self.player_2.draw(self.state)
|
||||
Reference in New Issue
Block a user