1
0
mirror of synced 2025-02-02 12:27:20 +01:00

Some bug fixes and feature additions (#5)

* fixed difficulty display in results screen

* added script to build release easier

* fixed some result screen issues and added judgement breakdown

* updated release script to use O2 and no debugging

* fixed judgement breakdown

* Implemented proper handling of hold note releases

* fixed hold notes

* removed early/late

* added easy build script for linux

* fixed density graph bug where goods were treated like combo breaks

* fixed typo

* reverted removal of judgement breakdown

* Update src/Data/GradedNote.cpp

Co-authored-by: Stepland <16676308+Stepland@users.noreply.github.com>

* Update src/Screens/Results/Results.cpp

Co-authored-by: Stepland <16676308+Stepland@users.noreply.github.com>

* Update src/Data/GradedNote.hpp

Co-authored-by: Stepland <16676308+Stepland@users.noreply.github.com>

* Update src/Drawables/GradedDensityGraph.cpp

Co-authored-by: Stepland <16676308+Stepland@users.noreply.github.com>

* Update src/Screens/Gameplay/Gameplay.cpp

Co-authored-by: Stepland <16676308+Stepland@users.noreply.github.com>

* fixed compile error

* uses copy_dependencies python script now for making a release archive

Co-authored-by: Seth Erfurt <serfurt@cs.utexas.edu>
Co-authored-by: Seth <seth@ske.moe>
Co-authored-by: Stepland <16676308+Stepland@users.noreply.github.com>
This commit is contained in:
Subject38 2020-07-22 07:47:04 -05:00 committed by GitHub
parent fd42ea7957
commit 0ae02b54fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 120 additions and 7 deletions

7
build_linux.sh Normal file
View File

@ -0,0 +1,7 @@
rm -rf build
mkdir build
meson build
meson configure build -Ddebug=false -Doptimization=2
cd build
ninja
cp ../assets assets -r

14
make_release.sh Normal file
View File

@ -0,0 +1,14 @@
rm -rf build
mkdir build
meson build
meson configure build -Ddebug=false -Doptimization=2
cd build
ninja
cp ../assets assets -r
../utils/copy_dependencies.py -f jujube.exe
rm -rf jujube@exe meson* build.ninja .ninja* compile_commands.json test
cd ..
zip jujube.zip -r build
mv -t build jujube.zip

View File

@ -35,11 +35,11 @@ namespace Data {
if (delta_abs < sf::Time::Zero) { if (delta_abs < sf::Time::Zero) {
delta_abs = -delta_abs; delta_abs = -delta_abs;
} }
if (delta_abs < sf::milliseconds(42)) { if (delta_abs < sf::milliseconds(40)) {
return Judgement::Perfect; return Judgement::Perfect;
} else if (delta_abs < sf::milliseconds(82)) { } else if (delta_abs < sf::milliseconds(80)) {
return Judgement::Great; return Judgement::Great;
} else if (delta_abs < sf::milliseconds(162)) { } else if (delta_abs < sf::milliseconds(160)) {
return Judgement::Good; return Judgement::Good;
} else if (delta_abs < sf::milliseconds(533)) { } else if (delta_abs < sf::milliseconds(533)) {
return Judgement::Poor; return Judgement::Poor;
@ -47,4 +47,33 @@ namespace Data {
return Judgement::Miss; return Judgement::Miss;
} }
} }
// implement the strange way in which jubeat judges hold note releases
Judgement release_to_judgement(const sf::Time& duration_held, const sf::Time& note_duration, const int tail_length) {
// if we implement hard mode we'll need a cleaner implementation of this since this would be 30. works for now though
int error_margin = 60;
// take the length of the note in ticks on a 300 hz clock and divide by length of tail in pixels
// logic taken from reversing the game's timing code
double milliseconds_to_300hz = 0.3;
auto note_duration_300hz = static_cast<double>(note_duration.asMilliseconds()) * milliseconds_to_300hz;
auto adjusted_note_duration = static_cast<int>(
note_duration_300hz * (1 - (static_cast<double>(error_margin) / (tail_length*195)))
);
// held for longer than duration : done
if((duration_held.asMilliseconds() * milliseconds_to_300hz) >= adjusted_note_duration) {
return Judgement::Perfect;
}
auto percentage_held = static_cast<int>(
duration_held.asMilliseconds() * milliseconds_to_300hz / adjusted_note_duration * 100
);
if (percentage_held < 100 and percentage_held >= 81) {
return Judgement::Great;
} else if (percentage_held < 80 and percentage_held >= 51) {
return Judgement::Good;
} else {
return Judgement::Poor;
}
}
} }

View File

@ -21,11 +21,21 @@ namespace Data {
Resources::MarkerAnimation judgement_to_animation(Judgement j); Resources::MarkerAnimation judgement_to_animation(Judgement j);
Judgement delta_to_judgement(const sf::Time& delta); Judgement delta_to_judgement(const sf::Time& delta);
Judgement release_to_judgement(const sf::Time& duration_held, const sf::Time& note_duration, const int tail_length);
struct TimedJudgement { struct TimedJudgement {
TimedJudgement() : delta(sf::Time::Zero), judgement(Judgement::Miss) {}; TimedJudgement() : delta(sf::Time::Zero), judgement(Judgement::Miss) {};
TimedJudgement(const sf::Time& d, const Judgement& j) : delta(d), judgement(j) {}; TimedJudgement(const sf::Time& d, const Judgement& j) : delta(d), judgement(j) {};
explicit TimedJudgement(const sf::Time& t) : delta(t), judgement(delta_to_judgement(t)) {}; explicit TimedJudgement(const sf::Time& t) : delta(t), judgement(delta_to_judgement(t)) {};
explicit TimedJudgement(
const sf::Time& duration_held,
const sf::Time& t,
const sf::Time& duration,
const int tail_length
) :
delta(t),
judgement(release_to_judgement(duration_held, duration, tail_length))
{};
sf::Time delta = sf::Time::Zero; sf::Time delta = sf::Time::Zero;
Judgement judgement = Judgement::Miss; Judgement judgement = Judgement::Miss;
}; };
@ -38,4 +48,4 @@ namespace Data {
std::optional<TimedJudgement> tap_judgement = {}; std::optional<TimedJudgement> tap_judgement = {};
std::optional<TimedJudgement> long_release = {}; std::optional<TimedJudgement> long_release = {};
}; };
} }

View File

@ -36,6 +36,10 @@ namespace Data {
return shutter; return shutter;
} }
int ClassicScore::get_judgement_counts(Judgement j) const {
return judgement_counts.at(j);
}
int ClassicScore::get_final_score() const { int ClassicScore::get_final_score() const {
return get_score() + shutter*100000/1024; return get_score() + shutter*100000/1024;
} }
@ -93,6 +97,8 @@ namespace Data {
case Judgement::Miss: case Judgement::Miss:
shutter_delta = shutter_decrement_4x; shutter_delta = shutter_decrement_4x;
break; break;
default:
break;
} }
shutter = std::clamp(shutter+shutter_delta, 0, 1024); shutter = std::clamp(shutter+shutter_delta, 0, 1024);
} }

View File

@ -51,6 +51,8 @@ namespace Data {
virtual Rating get_rating() const = 0; virtual Rating get_rating() const = 0;
// Update score according to the recieved judgement // Update score according to the recieved judgement
virtual void update(Judgement j) = 0; virtual void update(Judgement j) = 0;
// Get judgments
virtual int get_judgement_counts(Judgement j) const = 0;
}; };
std::size_t count_classic_scoring_events(const std::set<Note>& notes); std::size_t count_classic_scoring_events(const std::set<Note>& notes);
@ -64,6 +66,7 @@ namespace Data {
int get_score() const override; int get_score() const override;
Rating get_rating() const override; Rating get_rating() const override;
void update(Judgement j) override; void update(Judgement j) override;
int get_judgement_counts(Judgement j) const;
private: private:
int shutter = 0; int shutter = 0;
int shutter_incerment_2x; int shutter_incerment_2x;
@ -71,7 +74,6 @@ namespace Data {
int shutter_decrement_4x; int shutter_decrement_4x;
const std::size_t tap_event_count; const std::size_t tap_event_count;
std::unordered_map<Judgement, std::size_t> judgement_counts; std::unordered_map<Judgement, std::size_t> judgement_counts;
friend class Gameplay::Screen; friend class Gameplay::Screen;
}; };
} }

View File

@ -12,6 +12,7 @@ namespace Drawables {
case Data::Judgement::Perfect: case Data::Judgement::Perfect:
return DensityLineGrade::Perfect; return DensityLineGrade::Perfect;
case Data::Judgement::Great: case Data::Judgement::Great:
case Data::Judgement::Good:
return DensityLineGrade::Great; return DensityLineGrade::Great;
default: default:
return DensityLineGrade::ComboBreak; return DensityLineGrade::ComboBreak;

View File

@ -611,7 +611,12 @@ namespace Gameplay {
if (note.long_release) { if (note.long_release) {
continue; continue;
} }
auto timed_judgement = Data::TimedJudgement{music_time-note.timing-note.duration}; auto timed_judgement = Data::TimedJudgement{
music_time-note.timing,
music_time-note.timing-note.duration,
note.duration,
note.get_tail_length()
};
note.long_release = timed_judgement; note.long_release = timed_judgement;
score.update(timed_judgement.judgement); score.update(timed_judgement.judgement);
graded_density_graph.update_grades(timed_judgement.judgement, note.timing+note.duration); graded_density_graph.update_grades(timed_judgement.judgement, note.timing+note.duration);

View File

@ -25,6 +25,7 @@ namespace Results {
sf::Clock imgui_clock; sf::Clock imgui_clock;
auto final_score = score.get_final_score(); auto final_score = score.get_final_score();
auto final_rating = score.get_rating(); auto final_rating = score.get_rating();
while ((not should_exit) and window.isOpen()) { while ((not should_exit) and window.isOpen()) {
sf::Event event; sf::Event event;
while (window.pollEvent(event)) { while (window.pollEvent(event)) {
@ -54,6 +55,23 @@ namespace Results {
ImGui::SFML::Update(window, imgui_clock.restart()); ImGui::SFML::Update(window, imgui_clock.restart());
window.clear(sf::Color(7, 23, 53)); window.clear(sf::Color(7, 23, 53));
// Draw song info
// Cover is 40x40 @ (384,20)
if (song_selection.song.cover) {
auto cover = shared.covers.get(*song_selection.song.full_cover_path());
if (cover) {
sf::Sprite cover_sprite{*cover->texture};
auto cover_size = 40.f/768.f*get_screen_width();
Toolkit::set_size_from_local_bounds(cover_sprite, cover_size, cover_size);
cover_sprite.setPosition(
384.f/768.f*get_screen_width(),
20.f/768.f*get_screen_width()
);
window.draw(cover_sprite);
}
}
// White line under the density graph // White line under the density graph
sf::RectangleShape line{{get_screen_width()*1.1f,2.f/768.f*get_screen_width()}}; sf::RectangleShape line{{get_screen_width()*1.1f,2.f/768.f*get_screen_width()}};
Toolkit::set_origin_normalized(line, 0.5f, 0.5f); Toolkit::set_origin_normalized(line, 0.5f, 0.5f);
@ -93,6 +111,27 @@ namespace Results {
); );
window.draw(rating_text); window.draw(rating_text);
// Draw Judgement Breakdown
sf::Text judgements;
judgements.setFont(shared.fallback_font.black);
judgements.setFillColor(sf::Color(29, 98, 226));
std::string judgement_to_string = (
"Perfect: " + std::to_string(score.get_judgement_counts(Data::Judgement::Perfect)) + "\n" +
"Great: " + std::to_string(score.get_judgement_counts(Data::Judgement::Great)) + "\n" +
"Good: " + std::to_string(score.get_judgement_counts(Data::Judgement::Good)) + "\n" +
"Poor: " + std::to_string(score.get_judgement_counts(Data::Judgement::Poor)) + "\n" +
"Miss: " + std::to_string(score.get_judgement_counts(Data::Judgement::Miss))
);
judgements.setString(judgement_to_string);
judgements.setCharacterSize(static_cast<unsigned int>(0.1f*get_panel_size()));
Toolkit::set_local_origin_normalized(judgements, 0.5f, 0.5f);
judgements.setPosition(
get_ribbon_x()+0.f*get_panel_step()+0.5*get_panel_size(),
get_ribbon_y()+2.f*get_panel_step()+0.5*get_panel_size()
);
window.draw(judgements);
// Draw song info // Draw song info
auto song_title = song_selection.song.title; auto song_title = song_selection.song.title;
if (not song_title.empty()) { if (not song_title.empty()) {

View File

@ -25,7 +25,7 @@ namespace Results {
private: private:
Drawables::GradedDensityGraph graded_density_graph; Drawables::GradedDensityGraph graded_density_graph;
const Data::SongDifficulty& song_selection; const Data::SongDifficulty& song_selection;
const Data::Chart& chart; const Data::Chart chart;
const Data::AbstractScore& score; const Data::AbstractScore& score;
bool should_exit = false; bool should_exit = false;