├── .gitignore ├── gfx ├── don.png ├── top.png ├── bottom.png ├── katsu.png ├── roll_0.png ├── roll_1.png ├── roll_2.png ├── roll_3.png ├── roll_4.png ├── roll_5.png ├── roll_6.png ├── roll_7.png ├── roll_8.png ├── roll_9.png ├── balloon.png ├── big_don.png ├── combo_0.png ├── combo_1.png ├── combo_2.png ├── combo_3.png ├── combo_4.png ├── combo_5.png ├── combo_6.png ├── combo_7.png ├── combo_8.png ├── combo_9.png ├── roll_end.png ├── roll_int.png ├── score_0.png ├── score_1.png ├── score_2.png ├── score_3.png ├── score_4.png ├── score_5.png ├── score_6.png ├── score_7.png ├── score_8.png ├── score_9.png ├── soul_off.png ├── soul_on.png ├── balloon_0.png ├── balloon_1.png ├── balloon_2.png ├── balloon_3.png ├── balloon_4.png ├── balloon_5.png ├── balloon_6.png ├── big_katsu.png ├── combo_0_red.png ├── combo_1_red.png ├── combo_2_red.png ├── combo_3_red.png ├── combo_4_red.png ├── combo_5_red.png ├── combo_6_red.png ├── combo_7_red.png ├── combo_8_red.png ├── combo_9_red.png ├── effect_gogo.png ├── effect_nice.png ├── emblem_easy.png ├── emblem_edit.png ├── emblem_hard.png ├── emblem_oni.png ├── judge_bad.png ├── judge_nice.png ├── lane_expert.png ├── lane_master.png ├── roll_count.png ├── roll_fini.png ├── roll_start.png ├── soul_effect.png ├── balloon_count.png ├── big_roll_end.png ├── big_roll_fini.png ├── big_roll_int.png ├── chart_expert.png ├── chart_master.png ├── chart_normal.png ├── emblem_normal.png ├── judge_circle.png ├── judge_perfect.png ├── big_roll_start.png ├── effect_perfect.png ├── effect_special_nice.png ├── effect_special_perfect.png └── sprites.t3s ├── romfs ├── don.ogg ├── katsu.ogg ├── gfx │ └── sprites.t3x └── balloonbreak.ogg ├── resource ├── banner.bnr ├── banner.png ├── banner.wav ├── icon.png ├── banner.cgfx ├── bannertool.txt └── app.rsf ├── Build.bat ├── source ├── audio.h ├── result.h ├── time.h ├── main.h ├── vorbis.h ├── select.h ├── score.h ├── playback.h ├── notes.h ├── tja.h ├── result.cpp ├── vorbis.cpp ├── time.cpp ├── option.h ├── audio.cpp ├── header.h ├── playback.cpp ├── select.cpp ├── main.cpp ├── score.cpp ├── tja.cpp └── option.cpp ├── README.md ├── README_en.md └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.3dsx 3 | *.elf 4 | *.o 5 | *.smdh 6 | *.cia 7 | *.cxi -------------------------------------------------------------------------------- /gfx/don.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/don.png -------------------------------------------------------------------------------- /gfx/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/top.png -------------------------------------------------------------------------------- /gfx/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/bottom.png -------------------------------------------------------------------------------- /gfx/katsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/katsu.png -------------------------------------------------------------------------------- /gfx/roll_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_0.png -------------------------------------------------------------------------------- /gfx/roll_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_1.png -------------------------------------------------------------------------------- /gfx/roll_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_2.png -------------------------------------------------------------------------------- /gfx/roll_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_3.png -------------------------------------------------------------------------------- /gfx/roll_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_4.png -------------------------------------------------------------------------------- /gfx/roll_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_5.png -------------------------------------------------------------------------------- /gfx/roll_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_6.png -------------------------------------------------------------------------------- /gfx/roll_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_7.png -------------------------------------------------------------------------------- /gfx/roll_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_8.png -------------------------------------------------------------------------------- /gfx/roll_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_9.png -------------------------------------------------------------------------------- /romfs/don.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/romfs/don.ogg -------------------------------------------------------------------------------- /gfx/balloon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon.png -------------------------------------------------------------------------------- /gfx/big_don.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/big_don.png -------------------------------------------------------------------------------- /gfx/combo_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_0.png -------------------------------------------------------------------------------- /gfx/combo_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_1.png -------------------------------------------------------------------------------- /gfx/combo_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_2.png -------------------------------------------------------------------------------- /gfx/combo_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_3.png -------------------------------------------------------------------------------- /gfx/combo_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_4.png -------------------------------------------------------------------------------- /gfx/combo_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_5.png -------------------------------------------------------------------------------- /gfx/combo_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_6.png -------------------------------------------------------------------------------- /gfx/combo_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_7.png -------------------------------------------------------------------------------- /gfx/combo_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_8.png -------------------------------------------------------------------------------- /gfx/combo_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_9.png -------------------------------------------------------------------------------- /gfx/roll_end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_end.png -------------------------------------------------------------------------------- /gfx/roll_int.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_int.png -------------------------------------------------------------------------------- /gfx/score_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_0.png -------------------------------------------------------------------------------- /gfx/score_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_1.png -------------------------------------------------------------------------------- /gfx/score_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_2.png -------------------------------------------------------------------------------- /gfx/score_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_3.png -------------------------------------------------------------------------------- /gfx/score_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_4.png -------------------------------------------------------------------------------- /gfx/score_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_5.png -------------------------------------------------------------------------------- /gfx/score_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_6.png -------------------------------------------------------------------------------- /gfx/score_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_7.png -------------------------------------------------------------------------------- /gfx/score_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_8.png -------------------------------------------------------------------------------- /gfx/score_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/score_9.png -------------------------------------------------------------------------------- /gfx/soul_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/soul_off.png -------------------------------------------------------------------------------- /gfx/soul_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/soul_on.png -------------------------------------------------------------------------------- /romfs/katsu.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/romfs/katsu.ogg -------------------------------------------------------------------------------- /gfx/balloon_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_0.png -------------------------------------------------------------------------------- /gfx/balloon_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_1.png -------------------------------------------------------------------------------- /gfx/balloon_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_2.png -------------------------------------------------------------------------------- /gfx/balloon_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_3.png -------------------------------------------------------------------------------- /gfx/balloon_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_4.png -------------------------------------------------------------------------------- /gfx/balloon_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_5.png -------------------------------------------------------------------------------- /gfx/balloon_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_6.png -------------------------------------------------------------------------------- /gfx/big_katsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/big_katsu.png -------------------------------------------------------------------------------- /gfx/combo_0_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_0_red.png -------------------------------------------------------------------------------- /gfx/combo_1_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_1_red.png -------------------------------------------------------------------------------- /gfx/combo_2_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_2_red.png -------------------------------------------------------------------------------- /gfx/combo_3_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_3_red.png -------------------------------------------------------------------------------- /gfx/combo_4_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_4_red.png -------------------------------------------------------------------------------- /gfx/combo_5_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_5_red.png -------------------------------------------------------------------------------- /gfx/combo_6_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_6_red.png -------------------------------------------------------------------------------- /gfx/combo_7_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_7_red.png -------------------------------------------------------------------------------- /gfx/combo_8_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_8_red.png -------------------------------------------------------------------------------- /gfx/combo_9_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/combo_9_red.png -------------------------------------------------------------------------------- /gfx/effect_gogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/effect_gogo.png -------------------------------------------------------------------------------- /gfx/effect_nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/effect_nice.png -------------------------------------------------------------------------------- /gfx/emblem_easy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/emblem_easy.png -------------------------------------------------------------------------------- /gfx/emblem_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/emblem_edit.png -------------------------------------------------------------------------------- /gfx/emblem_hard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/emblem_hard.png -------------------------------------------------------------------------------- /gfx/emblem_oni.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/emblem_oni.png -------------------------------------------------------------------------------- /gfx/judge_bad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/judge_bad.png -------------------------------------------------------------------------------- /gfx/judge_nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/judge_nice.png -------------------------------------------------------------------------------- /gfx/lane_expert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/lane_expert.png -------------------------------------------------------------------------------- /gfx/lane_master.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/lane_master.png -------------------------------------------------------------------------------- /gfx/roll_count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_count.png -------------------------------------------------------------------------------- /gfx/roll_fini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_fini.png -------------------------------------------------------------------------------- /gfx/roll_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/roll_start.png -------------------------------------------------------------------------------- /gfx/soul_effect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/soul_effect.png -------------------------------------------------------------------------------- /resource/banner.bnr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/resource/banner.bnr -------------------------------------------------------------------------------- /resource/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/resource/banner.png -------------------------------------------------------------------------------- /resource/banner.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/resource/banner.wav -------------------------------------------------------------------------------- /resource/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/resource/icon.png -------------------------------------------------------------------------------- /gfx/balloon_count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/balloon_count.png -------------------------------------------------------------------------------- /gfx/big_roll_end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/big_roll_end.png -------------------------------------------------------------------------------- /gfx/big_roll_fini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/big_roll_fini.png -------------------------------------------------------------------------------- /gfx/big_roll_int.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/big_roll_int.png -------------------------------------------------------------------------------- /gfx/chart_expert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/chart_expert.png -------------------------------------------------------------------------------- /gfx/chart_master.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/chart_master.png -------------------------------------------------------------------------------- /gfx/chart_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/chart_normal.png -------------------------------------------------------------------------------- /gfx/emblem_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/emblem_normal.png -------------------------------------------------------------------------------- /gfx/judge_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/judge_circle.png -------------------------------------------------------------------------------- /gfx/judge_perfect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/judge_perfect.png -------------------------------------------------------------------------------- /resource/banner.cgfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/resource/banner.cgfx -------------------------------------------------------------------------------- /romfs/gfx/sprites.t3x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/romfs/gfx/sprites.t3x -------------------------------------------------------------------------------- /Build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | :start 4 | make 5 | echo Press any key to rebuild. 6 | pause 7 | goto start -------------------------------------------------------------------------------- /gfx/big_roll_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/big_roll_start.png -------------------------------------------------------------------------------- /gfx/effect_perfect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/effect_perfect.png -------------------------------------------------------------------------------- /resource/bannertool.txt: -------------------------------------------------------------------------------- 1 | Please download bannertool from https://github.com/Steveice10/bannertool/releases -------------------------------------------------------------------------------- /romfs/balloonbreak.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/romfs/balloonbreak.ogg -------------------------------------------------------------------------------- /gfx/effect_special_nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/effect_special_nice.png -------------------------------------------------------------------------------- /gfx/effect_special_perfect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/togetg/TJAPlayer_for_3DS/HEAD/gfx/effect_special_perfect.png -------------------------------------------------------------------------------- /source/audio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | void load_sound(); 3 | int play_sound(int id); 4 | void exit_music(); 5 | int music_SamplePos(int id); -------------------------------------------------------------------------------- /source/result.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct { 4 | 5 | int score,perfect, nice, bad, roll, combo; 6 | } RESULT_T; 7 | 8 | void draw_result(); -------------------------------------------------------------------------------- /source/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | double get_current_time(int id); 3 | void time_ini(); 4 | void draw_fps(); 5 | void stop_time(int id); 6 | void restart_time(int id); 7 | int get_time_isStop(int id); 8 | void toggle_time(int id); 9 | double calc_vorbis_time(double CurrentTimeNotes); -------------------------------------------------------------------------------- /source/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void draw_debug(float x, float y, const char *text); 4 | bool get_isPause(); 5 | void debug_touch(int x, int y); 6 | bool get_isMusicStart(); 7 | char* get_buffer(); 8 | int powi(int x, int y); 9 | int pause_window(touchPosition tp, unsigned int key); 10 | int message_window(touchPosition tp, unsigned int key,int text); 11 | 12 | #define BUFFER_SIZE 160 //バッファ用文字列のサイズ -------------------------------------------------------------------------------- /source/vorbis.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "playback.h" 6 | 7 | void setVorbis(struct decoder_fn* decoder); 8 | int initVorbis(const char* file); 9 | uint32_t rateVorbis(void); 10 | uint8_t channelVorbis(void); 11 | uint64_t decodeVorbis(void* buffer); 12 | void exitVorbis(void); 13 | //int playVorbis(const char* in, bool *p_isPlayMain); 14 | uint64_t fillVorbisBuffer(char* bufferOut); 15 | int isVorbis(const char* in); 16 | double getVorbisTime(); 17 | int get_buffer_size(); 18 | void put_buffer_size(int tmp); -------------------------------------------------------------------------------- /source/select.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "result.h" 3 | 4 | typedef struct { 5 | 6 | int level[5],x,y,tmp,genre; 7 | char title[256],path[256],tja[256],wave[256]; 8 | bool course[5],course_exist[5]; 9 | } LIST_T; 10 | 11 | typedef struct { 12 | 13 | int genre_color,font_color; 14 | char name[256], path[256]; 15 | bool isOpened; 16 | } GENRE_T; 17 | 18 | void disp_file_list(); 19 | void load_file_main(); 20 | void update_cursor(int knd); 21 | void get_SelectedId(LIST_T *TMP, int *arg); 22 | void draw_select_text(float x, float y, const char* text, int color = 0xffffff); 23 | bool get_isGameStart(); 24 | void select_ini(); 25 | void draw_option_text(float x, float y, const char *text, bool state, float *width, float *height,float sizex=0.7,float sizey = 0.7); 26 | void draw_result_text(float x, float y, float size, const char *text); 27 | void get_result(RESULT_T *Result); 28 | void calc_result_text(const char *text, float *width, float *height); -------------------------------------------------------------------------------- /source/score.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct { 4 | int perfect, nice, bad, 5 | score, norma, soul; 6 | 7 | }GAUGE_T; 8 | 9 | enum Judge_Knd { 10 | PERFECT = 0, 11 | SPECIAL_PERFECT, 12 | NICE, 13 | SPECIAL_NICE, 14 | BAD, 15 | THROUGH, 16 | ROLL, 17 | BIG_ROLL, 18 | ROLL_END, 19 | BALLOON, 20 | BALLOON_BREAK, 21 | }; 22 | 23 | void init_score(); 24 | void debug_score(); 25 | void update_score(int knd); 26 | void send_gogotime(bool temp); 27 | int round_down(int arg); 28 | void calc_base_score(MEASURE_T Measure[MEASURE_MAX], char tja_notes[MEASURE_MAX][NOTES_MEASURE_MAX]); 29 | void init_branch_section(); 30 | int start_branch(int knd, double x, double y); 31 | void draw_lane(C2D_Sprite sprites[SPRITES_NUMER]); 32 | void draw_gauge(C2D_Sprite sprites[SPRITES_NUMER]); 33 | void draw_score(C2D_Sprite sprites[SPRITES_NUMER]); 34 | void update_balloon_count(int arg); 35 | void draw_emblem(C2D_Sprite sprites[SPRITES_NUMER]); 36 | void draw_gauge_result(C2D_Sprite sprites[SPRITES_NUMER]); -------------------------------------------------------------------------------- /source/playback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "select.h" 4 | 5 | #define CHANNEL 5 6 | 7 | enum file_types{ 8 | FILE_TYPE_ERROR = -1, 9 | FILE_TYPE_WAV, 10 | FILE_TYPE_FLAC, 11 | FILE_TYPE_VORBIS, 12 | FILE_TYPE_OPUS, 13 | FILE_TYPE_MP3 14 | }; 15 | 16 | struct decoder_fn{ 17 | int (* init)(const char* file); 18 | uint32_t (* rate)(void); 19 | uint8_t (* channels)(void); 20 | size_t vorbis_buffer_size; 21 | uint64_t (* decode)(void*); 22 | void (* exit)(void); 23 | }; 24 | 25 | struct playbackInfo_t{ 26 | char* file; 27 | bool* isPlay; 28 | }; 29 | 30 | bool togglePlayback(void); 31 | void stopPlayback(void); 32 | bool isPlaying(void); 33 | int getFileType(const char *file); 34 | void playFile(void* infoIn); 35 | 36 | int changeFile(const char* ep_file, struct playbackInfo_t* playbackInfo,bool *p_isPlayMain); 37 | void play_main_music(bool *p_isPlayMain, LIST_T Song); 38 | void pasue_main_music(); 39 | void stop_main_music(); 40 | void init_main_music(); 41 | int check_wave(LIST_T Song); -------------------------------------------------------------------------------- /source/notes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tja.h" 3 | 4 | typedef struct { 5 | int num, notes_max, knd, roll_id; 6 | double x_ini, x, create_time, judge_time, pop_time, bpm, scroll; 7 | bool flag, isThrough; 8 | C2D_Sprite spr; 9 | 10 | } NOTES_T; 11 | 12 | typedef struct { 13 | int measure; 14 | double x, x_ini, create_time, scroll; 15 | bool flag, isDisp; 16 | 17 | } BARLINE_T; 18 | 19 | typedef struct { 20 | int id, start_id, end_id, knd; 21 | double start_x, end_x; 22 | bool flag; 23 | 24 | }ROLL_T; 25 | 26 | typedef struct { 27 | int id, start_id, end_id, 28 | need_hit, current_hit; 29 | bool flag; 30 | 31 | }BALLOON_T; 32 | 33 | typedef struct { 34 | int knd, course; 35 | double x, y; 36 | bool next, wait; 37 | 38 | }BRANCH_T; 39 | 40 | void notes_main( 41 | bool isDon, 42 | bool isKatsu, 43 | char tja_notes[MEASURE_MAX][NOTES_MEASURE_MAX], 44 | MEASURE_T Measure[MEASURE_MAX], 45 | int cnt, 46 | C2D_Sprite sprites[SPRITES_NUMER]); 47 | int ctoi(char c); 48 | int get_branch_course(); 49 | void init_notes(TJA_HEADER_T TJA_Header); 50 | bool get_notes_finish(); 51 | void draw_title(); -------------------------------------------------------------------------------- /source/tja.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "select.h" 3 | 4 | typedef struct { 5 | 6 | int knd, data[3],test; 7 | double val[3]; 8 | char* command_s,*notes,*value_s; 9 | } COMMAND_T; 10 | 11 | typedef struct { 12 | 13 | char *title, *subtitle,*wave; 14 | int level,balloon[256],songvol,sevol,scoreinit,scorediff, 15 | course,style,life,side,scoremode,total,subtitle_state; 16 | double bpm, offset, demostart; 17 | 18 | }TJA_HEADER_T; 19 | 20 | typedef struct { 21 | 22 | int knd; 23 | char* val; 24 | }HEADER_T; 25 | 26 | typedef struct { 27 | double judge_time, create_time, pop_time, 28 | bpm, speed,measure,scroll; 29 | int notes,firstmeasure,start_measure_count,max_notes,notes_count,command,branch, 30 | original_id; //ソート前のid 31 | bool flag,isDispBarLine; 32 | 33 | } MEASURE_T; 34 | 35 | void load_tja_head(int course, LIST_T Song); 36 | void load_tja_notes(int course, LIST_T Song); 37 | void tja_to_notes(bool isDnon, bool isKatsu, int count, C2D_Sprite sprites[SPRITES_NUMER]); 38 | void get_command_value(char* buf, COMMAND_T *Command); 39 | void get_tja_header(TJA_HEADER_T *TJA_Header); 40 | void init_tja(); 41 | double get_FirstMeasureTime(); 42 | int get_MeasureId_From_OriginalId(int id); 43 | bool get_isBranch(); 44 | void load_tja_head_simple(LIST_T *List); -------------------------------------------------------------------------------- /gfx/sprites.t3s: -------------------------------------------------------------------------------- 1 | --atlas -f rgba8888 -z auto 2 | top.png 3 | bottom.png 4 | don.png 5 | katsu.png 6 | big_don.png 7 | big_katsu.png 8 | roll_start.png 9 | roll_int.png 10 | roll_end.png 11 | big_roll_start.png 12 | big_roll_int.png 13 | big_roll_end.png 14 | balloon_0.png 15 | balloon_1.png 16 | balloon_2.png 17 | balloon_3.png 18 | balloon_4.png 19 | balloon_5.png 20 | balloon_6.png 21 | judge_perfect.png 22 | judge_nice.png 23 | judge_bad.png 24 | judge_circle.png 25 | chart_normal.png 26 | chart_expert.png 27 | chart_master.png 28 | lane_expert.png 29 | lane_master.png 30 | effect_perfect.png 31 | effect_special_perfect.png 32 | effect_nice.png 33 | effect_special_nice.png 34 | soul_on.png 35 | soul_off.png 36 | soul_effect.png 37 | effect_gogo.png 38 | score_0.png 39 | score_1.png 40 | score_2.png 41 | score_3.png 42 | score_4.png 43 | score_5.png 44 | score_6.png 45 | score_7.png 46 | score_8.png 47 | score_9.png 48 | combo_0.png 49 | combo_1.png 50 | combo_2.png 51 | combo_3.png 52 | combo_4.png 53 | combo_5.png 54 | combo_6.png 55 | combo_7.png 56 | combo_8.png 57 | combo_9.png 58 | combo_0_red.png 59 | combo_1_red.png 60 | combo_2_red.png 61 | combo_3_red.png 62 | combo_4_red.png 63 | combo_5_red.png 64 | combo_6_red.png 65 | combo_7_red.png 66 | combo_8_red.png 67 | combo_9_red.png 68 | roll_0.png 69 | roll_1.png 70 | roll_2.png 71 | roll_3.png 72 | roll_4.png 73 | roll_5.png 74 | roll_6.png 75 | roll_7.png 76 | roll_8.png 77 | roll_9.png 78 | roll_count.png 79 | balloon_count.png 80 | emblem_easy.png 81 | emblem_normal.png 82 | emblem_hard.png 83 | emblem_oni.png 84 | emblem_edit.png -------------------------------------------------------------------------------- /source/result.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "result.h" 3 | #include "select.h" 4 | #include "option.h" 5 | #include "tja.h" 6 | #include "main.h" 7 | 8 | RESULT_T result; 9 | 10 | void draw_result() { 11 | 12 | TJA_HEADER_T Tja; 13 | get_tja_header(&Tja); 14 | get_result(&result); 15 | 16 | float size = 0.7,width,height; 17 | 18 | draw_result_text(50, 10,size, Tja.title); 19 | draw_result_text(50, 30, size*0.8,Tja.subtitle); 20 | 21 | int iniX=100,iniY = 100, x2 = 300,YSense = 20, count = 0; 22 | draw_result_text(iniX, iniY + YSense * count, size, Text[get_lang()][TEXT_SCORE]); 23 | snprintf(get_buffer(), BUFFER_SIZE, "%d", result.score); 24 | calc_result_text(get_buffer(), &width, &height); 25 | draw_result_text(x2 - width, iniY + YSense * count, size, get_buffer()); 26 | count++; 27 | draw_result_text(iniX, iniY + YSense * count, size,Text[get_lang()][TEXT_PERFECT]); 28 | snprintf(get_buffer(), BUFFER_SIZE, "%d", result.perfect); 29 | calc_result_text(get_buffer(), &width, &height); 30 | draw_result_text(x2 - width, iniY + YSense * count, size, get_buffer()); 31 | count++; 32 | draw_result_text(iniX, iniY + YSense * count, size,Text[get_lang()][TEXT_NICE]); 33 | snprintf(get_buffer(), BUFFER_SIZE, "%d", result.nice); 34 | calc_result_text(get_buffer(), &width, &height); 35 | draw_result_text(x2 - width, iniY + YSense * count, size, get_buffer()); 36 | count++; 37 | draw_result_text(iniX, iniY + YSense * count, size,Text[get_lang()][TEXT_BAD]); 38 | snprintf(get_buffer(), BUFFER_SIZE, "%d", result.bad); 39 | calc_result_text(get_buffer(), &width, &height); 40 | draw_result_text(x2 - width, iniY + YSense * count, size, get_buffer()); 41 | count++; 42 | draw_result_text(iniX, iniY + YSense * count, size,Text[get_lang()][TEXT_ROLLCOUNT]); 43 | snprintf(get_buffer(), BUFFER_SIZE, "%d", result.roll); 44 | calc_result_text(get_buffer(), &width, &height); 45 | draw_result_text(x2 - width, iniY + YSense * count, size, get_buffer()); 46 | count++; 47 | draw_result_text(iniX, iniY + YSense * count, size,Text[get_lang()][TEXT_MAXCOMBO]); 48 | snprintf(get_buffer(), BUFFER_SIZE, "%d", result.combo); 49 | calc_result_text(get_buffer(), &width, &height); 50 | draw_result_text(x2 - width, iniY + YSense * count, size, get_buffer()); 51 | count++; 52 | draw_result_text(3, TOP_HEIGHT - 15, 0.5, Text[get_lang()][TEXT_PRESSSTART]); 53 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [English](README_en.md) 2 |
3 | banner 4 |
5 | 6 | 太鼓さん次郎等で使われている[TJAファイル](https://wikiwiki.jp/jiro/%E5%A4%AA%E9%BC%93%E3%81%95%E3%82%93%E6%AC%A1%E9%83%8E#h2_content_1_8)を3DSでプレイします。 7 | 8 | # 使い方 9 | 10 | ## 譜面の追加 11 | 12 | 1. **TJAファイルの文字コードをUFT-8に変換します。**
この作業は[KanjiTranslator](https://www.kashim.com/kanjitranslator/)等を使って一括で行うことをオススメします。
TITLEやWAVEに日本語などのマルチバイト文字が含まれていない場合はこの作業は必要ありません。 13 | 2. 3DSのSDカードのルートに「tjafiles」というフォルダを作り、その中にTJAファイルと音源ファイルを入れてください。 14 | 15 | ## ジャンル機能 16 | 17 | フォルダ内に以下のような「genre.json」を置くとジャンルとして認識します。 18 | 19 | ```json 20 | { 21 | "GenreName":"ジャンル", 22 | "GenreColor": "#d3c442", 23 | "FontColor": "#ff0000" 24 | } 25 | ``` 26 | 27 | # 注意 28 | 29 | - **音楽が遅れる、音楽が途切れる時はバッファサイズを大きく設定してください。(フレームレートは低下します)**
ビットレートが64Kbps、サンプルレートが32000Hzの音楽ファイルは8000程度のバッファサイズで再生できます。 30 | - 音源ファイルはOggファイルのみ対応してます。 31 | - ノーツ音と音源が全く聞こえない時は[DSP1](https://github.com/zoogie/DSP1/releases)を起動してください。 32 | 33 | # 対応していない機能 34 | 35 | - ノーツ 36 | - イモ連打(ドン音符に置き換え) 37 | - ヘッダ 38 | - SONGVOL 39 | - SEVOL 40 | - STYLE 41 | - LIFE 42 | - DEMOSTART 43 | - TOTAL 44 | - 命令 45 | - BMSCROLL 46 | - HBSCROLL 47 | - その他 48 | - TJCフォーマット 49 | - TJFフォーマット 50 | - スコアの保存 51 | 52 | # スクリーンショット 53 |
スクリーンショット 54 | 55 | ![1](https://user-images.githubusercontent.com/18244518/120986498-a3718300-c7b7-11eb-9036-8d9807a1b5c0.png) ![2](https://user-images.githubusercontent.com/18244518/120986505-a66c7380-c7b7-11eb-9c61-d98f752e9f2d.png) 56 | ![3](https://user-images.githubusercontent.com/18244518/120986516-a8363700-c7b7-11eb-83af-db1fe4a3de32.png) ![4](https://user-images.githubusercontent.com/18244518/120986526-a9fffa80-c7b7-11eb-99a4-0756e8dae4db.png) 57 | ![5](https://user-images.githubusercontent.com/18244518/120986545-ad938180-c7b7-11eb-89ad-bafca4c2c441.png) 58 | 59 |
60 | 61 | # ビルド 62 | 1. [devkitPro](https://github.com/devkitPro/installer/releases/)をインストール 63 | 64 | 2. 以下のコマンドでパッケージをインストール 65 | 66 | `pacman -S 3ds-libogg 3ds-dev 3ds-libvorbisidec 3ds-jansson --noconfirm` 67 | 68 | 3. [MakeROM](https://github.com/3DSGuy/Project_CTR/releases)と[bannertool](https://github.com/Steveice10/bannertool/releases)をダウンロードしPATHを通す 69 | 70 | 4. Build.batを起動、もしくは以下のコマンドを実行 71 | 72 | `make` 73 | 74 | # クレジット 75 | - [ManOfNoWonder](https://github.com/ManOfNoWonder) - 英語翻訳 76 | -------------------------------------------------------------------------------- /source/vorbis.cpp: -------------------------------------------------------------------------------- 1 | #include <3ds.h> 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "main.h" 8 | #include "vorbis.h" 9 | #include "header.h" 10 | 11 | static OggVorbis_File vorbisFile; 12 | static vorbis_info *vi; 13 | static FILE *f; 14 | size_t vorbis_buffer_size = DEFAULT_BUFFER_SIZE;// 8 * 4096; 15 | 16 | void setVorbis(struct decoder_fn* decoder){ 17 | decoder->init = &initVorbis; 18 | decoder->rate = &rateVorbis; 19 | decoder->channels = &channelVorbis; 20 | decoder->vorbis_buffer_size = vorbis_buffer_size; 21 | decoder->decode = &decodeVorbis; 22 | decoder->exit = &exitVorbis; 23 | } 24 | 25 | int initVorbis(const char* file){ 26 | int err = -1; 27 | 28 | if((f = fopen(file, "rb")) == NULL) 29 | goto out; 30 | 31 | if(ov_open(f, &vorbisFile, NULL, 0) < 0) 32 | goto out; 33 | 34 | if((vi = ov_info(&vorbisFile, -1)) == NULL) 35 | goto out; 36 | 37 | err = 0; 38 | 39 | out: 40 | return err; 41 | } 42 | 43 | 44 | uint32_t rateVorbis(void){ 45 | return vi->rate; 46 | } 47 | 48 | uint8_t channelVorbis(void) 49 | { 50 | return vi->channels; 51 | } 52 | 53 | uint64_t decodeVorbis(void* buffer) 54 | { 55 | return fillVorbisBuffer((char*)buffer); 56 | } 57 | 58 | void exitVorbis(void) 59 | { 60 | ov_clear(&vorbisFile); 61 | fclose(f); 62 | } 63 | 64 | double vorbis_time = 0; 65 | 66 | uint64_t fillVorbisBuffer(char* bufferOut) 67 | { 68 | uint64_t samplesRead = 0; 69 | int samplesToRead = vorbis_buffer_size; 70 | 71 | while(samplesToRead > 0) 72 | { 73 | static int current_section; 74 | int samplesJustRead = 75 | ov_read(&vorbisFile, bufferOut, 76 | samplesToRead > 4096 ? 4096 : samplesToRead, 77 | ¤t_section); 78 | 79 | if(samplesJustRead < 0) 80 | return samplesJustRead; 81 | else if(samplesJustRead == 0){ 82 | break; 83 | } 84 | 85 | samplesRead += samplesJustRead; 86 | samplesToRead -= samplesJustRead; 87 | bufferOut += samplesJustRead; 88 | } 89 | //vorbis_time = (double)ov_time_tell(&vorbisFile)/1000.0; 90 | return samplesRead / sizeof(int16_t); 91 | } 92 | 93 | int isVorbis(const char *in){ 94 | FILE *ft = fopen(in, "r"); 95 | OggVorbis_File testvf; 96 | int err; 97 | 98 | if(ft == NULL) 99 | return -1; 100 | 101 | err = ov_test(ft, &testvf, NULL, 0); 102 | 103 | ov_clear(&testvf); 104 | fclose(ft); 105 | return err; 106 | } 107 | 108 | double getVorbisTime() { 109 | 110 | if (get_isMusicStart() == true) return vorbis_time = (double)ov_time_tell(&vorbisFile) / 1000.0; //再生前に呼び出すとクラッシュ 111 | else return -1000; 112 | } 113 | 114 | int get_buffer_size() { 115 | return (int)vorbis_buffer_size; 116 | } 117 | 118 | void put_buffer_size(int tmp) { 119 | vorbis_buffer_size = (size_t)tmp; 120 | } -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | [日本語](README.md) 2 |
3 | banner 4 |
5 | 6 | It's a music game of the [TJA file](https://wikiwiki.jp/jiro/%E5%A4%AA%E9%BC%93%E3%81%95%E3%82%93%E6%AC%A1%E9%83%8E#h2_content_1_8) used by Taiko Jiro on 3DS. 7 | 8 | # Usage 9 | 10 | ## Add TJA files 11 | 12 | 1. **Convert character code of TJA file to UFT-8.**
I recommend that you do this task collectively with [KanjiTranslator](https://www.kashim.com/kanjitranslator/) etc.
If "TITLE" and "WAVE" don't contain multibyte characters such as Japanese, this work isn't necessary. 13 | 2. Create a folder named "tjafiles" in the root of the SD card of 3DS, and put in the TJA file and the sound file in it. 14 | 15 | ## Genre 16 | 17 | If you put the following "genre.json" in the folder, it will be recognized as a genre. 18 | 19 | ```json 20 | { 21 | "GenreName":"ジャンル", 22 | "GenreColor": "#d3c442", 23 | "FontColor": "#ff0000" 24 | } 25 | ``` 26 | 27 | # Note 28 | 29 | - **If the music is delayed, set a larger buffer size.(This will reduce the frame rate.)**
A music file with a bit rate of 64Kbps and a sample rate of 32000Hz can be played with a buffer size of about 8000. 30 | - Only the Ogg file is supported for the sound file. 31 | - If you don't hearh the notes sound and music at all, start up [DSP1](https://github.com/zoogie/DSP1/releases). 32 | 33 | # Not supported 34 | 35 | - Note 36 | - Potato roll (Replace it with Don note) 37 | - Header 38 | - SONGVOL 39 | - SEVOL 40 | - STYLE 41 | - LIFE 42 | - DEMOSTART 43 | - TOTAL 44 | - Command 45 | - BMSCROLL 46 | - HBSCROLL 47 | - Other 48 | - TJC format 49 | - TJF format 50 | - Save score 51 | 52 | # Screenshots 53 |
Screenshots 54 | 55 | ![1](https://user-images.githubusercontent.com/18244518/121764654-886c8d80-cb80-11eb-9ab0-db90cbe2c989.png) ![2](https://user-images.githubusercontent.com/18244518/121764656-8dc9d800-cb80-11eb-8c21-be6b99fc4b0e.png) 56 | ![3](https://user-images.githubusercontent.com/18244518/121764658-90c4c880-cb80-11eb-8ee2-af9dc31e5ea7.png) ![4](https://user-images.githubusercontent.com/18244518/121764661-94584f80-cb80-11eb-96b6-31237baea857.png) 57 | ![5](https://user-images.githubusercontent.com/18244518/121764663-97ebd680-cb80-11eb-9ab7-c24bc7f5f8bb.png) 58 | 59 |
60 | 61 | # How to Build 62 | 1. Install [devkitPro](https://github.com/devkitPro/installer/releases/) 63 | 64 | 2. Install the package with the following command 65 | 66 | `pacman -S 3ds-libogg 3ds-dev 3ds-libvorbisidec 3ds-jansson --noconfirm` 67 | 68 | 3. Download [MakeROM](https://github.com/3DSGuy/Project_CTR/releases) and [bannertool](https://github.com/Steveice10/bannertool/releases) and set the PATH. 69 | 70 | 4. Run Build.bat or execute the following command 71 | 72 | `make` 73 | 74 | # Credits 75 | - [ManOfNoWonder](https://github.com/ManOfNoWonder) - English Translation 76 | -------------------------------------------------------------------------------- /source/time.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "main.h" 3 | #include "vorbis.h" 4 | #include "tja.h" 5 | #include "time.h" 6 | #include 7 | 8 | enum msec_status { 9 | MSEC_INIT, 10 | MSEC_CURRENT, 11 | MSEC_DIFF, 12 | MSEC_LAST_DIFF, 13 | }; 14 | #define TIME_NUM 5 15 | 16 | struct timeval myTime; 17 | int cnt[TIME_NUM], msec[TIME_NUM][4], sec[TIME_NUM]; 18 | int isStop[TIME_NUM]; 19 | double PreTime[TIME_NUM],Time[TIME_NUM],CurrentTime[TIME_NUM],IniVorbisTime[TIME_NUM]; 20 | 21 | double get_current_time(int id) { 22 | 23 | if ((id == 0 || id == 1) && get_isMusicStart() == true) { //メインのカウントの時はVorbis基準の時間を返す 要曲終了時の処理 24 | //if (isStop[id] != 1) stop_time(id); 25 | if (CurrentTime[id] == 0 && Time[id] == 0 && IniVorbisTime[id]==0) IniVorbisTime[id] = getVorbisTime(); 26 | CurrentTime[id] = Time[id] + getVorbisTime() - IniVorbisTime[id]; 27 | //return CurrentTime[id]; 28 | //snprintf(get_buffer(), BUFFER_SIZE, "vbt:%.1f", CurrentTime[id]); 29 | //draw_debug(100, id*10, get_buffer()); 30 | } 31 | 32 | if (isStop[id] != 1) { 33 | gettimeofday(&myTime, NULL); 34 | 35 | if (cnt[id] == 0) msec[id][MSEC_INIT] = (int)myTime.tv_usec; 36 | 37 | msec[id][MSEC_CURRENT] = (int)myTime.tv_usec; 38 | msec[id][MSEC_LAST_DIFF] = msec[id][MSEC_DIFF]; 39 | msec[id][MSEC_DIFF] = msec[id][MSEC_CURRENT] - msec[id][MSEC_INIT]; 40 | 41 | if (msec[id][MSEC_DIFF] < 0) msec[id][MSEC_DIFF] = 1000000 - msec[id][MSEC_DIFF] * -1; 42 | 43 | if (msec[id][MSEC_LAST_DIFF] > msec[id][MSEC_DIFF]) sec[id]++; 44 | 45 | cnt[id]++; 46 | //printf("%04d:%06d\n", sec, msec[id][MSEC_DIFF]); 47 | Time[id] = sec[id] + msec[id][MSEC_DIFF] / 1000000.0 + PreTime[id]; 48 | } 49 | //snprintf(get_buffer(), BUFFER_SIZE, "t:%.1f", Time[id]); 50 | //draw_debug(0, id*10, get_buffer()); 51 | return Time[id]; 52 | } 53 | 54 | void restart_time(int id) { 55 | isStop[id] = 0; 56 | } 57 | 58 | void stop_time(int id) { 59 | 60 | isStop[id] = 1; 61 | for (int n = 0; n < 4; n++) { 62 | msec[id][n] = 0; 63 | } 64 | 65 | PreTime[id] = Time[id] += 0.0178; 66 | sec[id] = 0; 67 | cnt[id] = 0; 68 | } 69 | 70 | void toggle_time(int id) { 71 | 72 | if (Time[id] != 0) { 73 | if (isStop[id] == 1) restart_time(id); 74 | else stop_time(id); 75 | } 76 | } 77 | 78 | int get_time_isStop(int id) { 79 | return isStop[id]; 80 | } 81 | 82 | #define FPS_SAMPLE 20 83 | double fps_time[2],fps_cnt,fps_sum,fps; //要初期化 84 | void draw_fps() { 85 | 86 | fps_time[0] = fps_time[1]; 87 | fps_time[1] = get_current_time(TIME_FPS); 88 | 89 | fps_sum += (fps_time[1] - fps_time[0]); 90 | fps_cnt++; 91 | 92 | if (fps_cnt == FPS_SAMPLE) { 93 | fps_cnt = 0; 94 | fps = FPS_SAMPLE / fps_sum; 95 | fps_sum = 0; 96 | } 97 | snprintf(get_buffer(), BUFFER_SIZE, "%.1ffps", fps); 98 | draw_debug(300, 0, get_buffer()); 99 | } 100 | 101 | double preVorbisTime = -1000,startVorbisTime = -1000; 102 | double calc_vorbis_time(double CurrentTimeNotes) { 103 | 104 | double result,vorbisTime = getVorbisTime(); 105 | if (vorbisTime == -1000) result = CurrentTimeNotes; //曲開始前はそのまま返す 106 | if (preVorbisTime == -1000 && vorbisTime != -1000) startVorbisTime = CurrentTimeNotes;//曲開始時間を保存(timenotes換算) 107 | if (vorbisTime != -1000) result = vorbisTime + startVorbisTime; 108 | 109 | preVorbisTime = vorbisTime; 110 | return result; 111 | } 112 | 113 | void time_ini() { 114 | 115 | for (int i = 0; i < TIME_NUM; i++) { 116 | 117 | for (int n = 0; n < 4; n++) { 118 | msec[i][n] = 0; 119 | 120 | } 121 | 122 | sec[i] = 0; 123 | cnt[i] = 0; 124 | isStop[i] = 0; 125 | PreTime[i] = 0; 126 | Time[i] = 0; 127 | CurrentTime[i] = 0; 128 | IniVorbisTime[i] = 0; 129 | } 130 | fps_time[0] = 0; 131 | fps_time[1] = 0; 132 | fps_cnt = 0; 133 | fps_sum = 0; 134 | fps = 0; 135 | preVorbisTime = -1000; 136 | startVorbisTime = -1000; 137 | } -------------------------------------------------------------------------------- /source/option.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | const char Text[3][64][128] = { 4 | { 5 | "ON", 6 | "OFF", 7 | "かんたん", 8 | "ふつう", 9 | "むずかしい", 10 | "おに", 11 | "オート", 12 | "はやさ", 13 | "x1", 14 | "x2", 15 | "x3", 16 | "x4", 17 | "ステルス", 18 | "あべこべ", 19 | "ランダム", 20 | "25%", 21 | "50%", 22 | "Lang.", 23 | "日本語", 24 | "English", 25 | "Español", 26 | "バッファサイズ", 27 | "リセット", 28 | "fps表示", 29 | "ボタン割り当て", 30 | "スコア", 31 | "最大コンボ数", 32 | "良", 33 | "可", 34 | "不可", 35 | "連打数", 36 | "STARTボタンを押して戻る", 37 | "演奏を続ける", 38 | "はじめからやり直す", 39 | "曲選択に戻る", 40 | "DSP1を起動していないため音は流れません", 41 | "音楽ファイルが読み込めません\n\nTJAファイルをUTF-8に変換しましたか?", 42 | "音楽ファイルがOggファイルではありません", 43 | }, 44 | { 45 | "ON", 46 | "OFF", 47 | "Easy", 48 | "Normal", 49 | "Hard", 50 | "Extreme", 51 | "Auto", 52 | "Speed", 53 | "x1", 54 | "x2", 55 | "x3", 56 | "x4", 57 | "Vanish", 58 | "Inverse", 59 | "Random", 60 | "25%", 61 | "50%", 62 | "Lang.", 63 | "日本語", 64 | "English", 65 | "Español", 66 | "BufferSize", 67 | "Reset", 68 | "Display fps", 69 | "Button mapping", 70 | "Score", 71 | "MAX Combo", 72 | "GOOD", 73 | "OK", 74 | "BAD", 75 | "Drumroll", 76 | "Press START", 77 | "Continue", 78 | "Retry", 79 | "Back to Select song", 80 | "No sound is played because\nDSP1 is not activated.", 81 | "The sound file does not exist.\n\nHave you converted the character encoding\nof the TJA file to UTF8?", 82 | "The sound file is not an Ogg file.", 83 | }, 84 | { 85 | "Sí", 86 | "No", 87 | "Fácil", 88 | "Normal", 89 | "Difícil", 90 | "Extremo", 91 | "Auto", 92 | "Velocidad", 93 | "x1", 94 | "x2", 95 | "x3", 96 | "x4", 97 | "Invisible", 98 | "Inversa", 99 | "Random", 100 | "25%", 101 | "50%", 102 | "Idioma", 103 | "日本語", 104 | "English", 105 | "Español", 106 | "Tamaño del búfer", 107 | "Reiniciar", 108 | "Mostrar fps", 109 | "Mapeo de botones", 110 | "Puntuación", 111 | "Combo máximo", 112 | "Bien", 113 | "OK", 114 | "Mal", 115 | "Redoble", 116 | "Presiona START", 117 | "Continuar", 118 | "Reintentar", 119 | "Volver al menú", 120 | "No sound is played because\nDSP1 is not activated.", 121 | "The sound file does not exist.\n\nHave you converted the character encoding\nof the TJA file to UTF8?", 122 | "The sound file is not an Ogg file.", 123 | } 124 | }; 125 | 126 | typedef struct { 127 | 128 | int lang,buffer_size; 129 | bool isAuto, isStelth,isSwap,dispFps; 130 | double speed, random,offset, 131 | judge_range_perfect,judge_range_nice,judge_range_bad; 132 | int KEY_A, KEY_B, KEY_DRIGHT, KEY_DLEFT, KEY_DUP, KEY_DDOWN, KEY_R, KEY_L, KEY_X, KEY_Y, 133 | KEY_ZL, KEY_ZR, KEY_CSTICK_RIGHT, KEY_CSTICK_LEFT, KEY_CSTICK_UP, KEY_CSTICK_DOWN, 134 | KEY_CPAD_RIGHT, KEY_CPAD_LEFT, KEY_CPAD_UP, KEY_CPAD_DOWN; 135 | } OPTION_T; 136 | 137 | enum Lang_knd { 138 | LANG_JP = 0, 139 | LANG_EN, 140 | LANG_ES, 141 | }; 142 | 143 | enum KEY_KND { 144 | KEY_NONE = 0, 145 | KEY_DON, 146 | KEY_KATSU, 147 | }; 148 | 149 | enum Text_knd { 150 | TEXT_ON, 151 | TEXT_OFF, 152 | TEXT_EASY, 153 | TEXT_NORMAL, 154 | TEXT_HARD, 155 | TEXT_ONI, 156 | TEXT_AUTO, 157 | TEXT_SPEED, 158 | TEXT_X1, 159 | TEXT_X2, 160 | TEXT_X3, 161 | TEXT_X4, 162 | TEXT_STELTH, 163 | TEXT_SWAP, 164 | TEXT_RANDOM, 165 | TEXT_R25, 166 | TEXT_R50, 167 | TEXT_LANG, 168 | TEXT_JP, 169 | TEXT_EN, 170 | TEXT_ES, 171 | TEXT_BUFFERSIZE, 172 | TEXT_RESET, 173 | TEXT_DISP_FPS, 174 | TEXT_BUTTON_MAPPING, 175 | TEXT_SCORE, 176 | TEXT_MAXCOMBO, 177 | TEXT_PERFECT, 178 | TEXT_NICE, 179 | TEXT_BAD, 180 | TEXT_ROLLCOUNT, 181 | TEXT_PRESSSTART, 182 | TEXT_CONTINUE, 183 | TEXT_STARTOVER, 184 | TEXT_RETURNSELECT, 185 | TEXT_WARNING_DSP1, 186 | TEXT_WARNING_WAVE_NO_EXIST, 187 | TEXT_WARNING_WAVE_NOT_OGG, 188 | }; 189 | 190 | int get_lang(); 191 | void draw_option(u16 px, u16 py, unsigned int key , C2D_Sprite sprites[SPRITES_NUMER]); 192 | void toggle_auto(); 193 | void get_option(OPTION_T *TMP); 194 | void init_option(); 195 | void load_option(),exit_option(),save_option(); -------------------------------------------------------------------------------- /source/audio.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "header.h" 5 | 6 | #define AUDIO_BUFFER_SIZE 4096 7 | #define STACKSIZE (4 * 1024) 8 | #define SOUND_NUMBER 3 9 | 10 | typedef struct { 11 | float rate; 12 | u32 channels; 13 | u32 encoding; 14 | u32 nsamples; 15 | u32 size; 16 | char* data; 17 | bool loop; 18 | int audiochannel; 19 | float mix[12]; 20 | ndspInterpType interp; 21 | OggVorbis_File ovf; 22 | } Sound; 23 | Sound sound[SOUND_NUMBER]; 24 | ndspWaveBuf waveBuf[SOUND_NUMBER]; 25 | 26 | void load_sound() { 27 | 28 | ndspInit(); 29 | ndspSetOutputMode(NDSP_OUTPUT_STEREO); 30 | ndspSetOutputCount(1); 31 | char sound_address[SOUND_NUMBER][30] = { 32 | "romfs:/don.ogg", 33 | "romfs:/katsu.ogg", 34 | "romfs:/balloonbreak.ogg", 35 | }; 36 | 37 | for (int i = 0; i < SOUND_NUMBER; i++) { 38 | memset(&sound[i], 0, sizeof(sound[i])); 39 | sound[i].mix[0] = 1.0f; 40 | sound[i].mix[1] = 1.0f; 41 | FILE * file = fopen(sound_address[i], "rb"); 42 | if (file == 0) { 43 | printf("no file\n"); 44 | while (1); 45 | } 46 | if (ov_open(file, &sound[i].ovf, NULL, 0) < 0) { 47 | printf("ogg vorbis file error\n"); 48 | while (1); 49 | } 50 | vorbis_info * vorbisInfo = ov_info(&sound[i].ovf, -1); 51 | if (vorbisInfo == NULL) { 52 | printf("could not retrieve ogg audio stream information\n"); 53 | while (1); 54 | } 55 | sound[i].rate = (float)vorbisInfo->rate; 56 | sound[i].channels = (u32)vorbisInfo->channels; 57 | sound[i].encoding = NDSP_ENCODING_PCM16; 58 | sound[i].nsamples = (u32)ov_pcm_total(&sound[i].ovf, -1); 59 | sound[i].size = sound[i].nsamples * sound[i].channels * 2; 60 | sound[i].audiochannel = i; 61 | sound[i].interp = NDSP_INTERP_NONE; 62 | sound[i].loop = false; 63 | if (linearSpaceFree() < sound[i].size) { 64 | printf("not enough linear memory available %ld\n", sound[i].size); 65 | } 66 | sound[i].data = (char*)linearAlloc(sound[i].size); 67 | if (sound[i].data == 0) { 68 | printf("null\n"); 69 | while (1); 70 | } 71 | /*printf("rate:%f\n", sound[i].rate); 72 | printf("channels:%ld\n", sound[i].channels); 73 | printf("encoding:%ld\n", sound[i].encoding); 74 | printf("nsamples:%ld\n", sound[i].nsamples); 75 | printf("size:%ld\n", sound[i].size); 76 | printf("Now Loading...");*/ 77 | int offset = 0; 78 | int eof = 0; 79 | int currentSection; 80 | while (!eof) { 81 | long ret = ov_read(&sound[i].ovf, &sound[i].data[offset], AUDIO_BUFFER_SIZE, ¤tSection); 82 | if (ret == 0) { 83 | eof = 1; 84 | } 85 | else if (ret < 0) { 86 | ov_clear(&sound[i].ovf); 87 | linearFree(sound[i].data); 88 | printf("error in the ogg vorbis stream\n"); 89 | while (1); 90 | } 91 | else { 92 | offset += ret; 93 | } 94 | //printf("%ld %d\n", ret, currentSection); 95 | } 96 | memset(&waveBuf[i], 0, sizeof(ndspWaveBuf)); 97 | waveBuf[i].data_vaddr = sound[i].data; 98 | waveBuf[i].nsamples = sound[i].nsamples; 99 | waveBuf[i].looping = sound[i].loop; 100 | waveBuf[i].status = NDSP_WBUF_FREE; 101 | DSP_FlushDataCache(sound[i].data, sound[i].size); 102 | //linearFree(&sound[i].ovf); 103 | ov_clear(&sound[i].ovf); 104 | fclose(file); 105 | } 106 | } 107 | int play_sound(int id) { 108 | 109 | if (sound[id].audiochannel == -1) { 110 | printf("No available audio channel\n"); 111 | return -1; 112 | } 113 | ndspChnWaveBufClear(sound[id].audiochannel); 114 | ndspChnReset(sound[id].audiochannel); 115 | ndspChnInitParams(sound[id].audiochannel); 116 | ndspChnSetMix(sound[id].audiochannel, sound[id].mix); 117 | ndspChnSetInterp(sound[id].audiochannel, sound[id].interp); 118 | ndspChnSetRate(sound[id].audiochannel, sound[id].rate); 119 | ndspChnSetFormat(sound[id].audiochannel, NDSP_CHANNELS(sound[id].channels) | NDSP_ENCODING(sound[id].encoding)); 120 | ndspChnWaveBufAdd(sound[id].audiochannel, &waveBuf[id]); 121 | 122 | return 0; 123 | } 124 | 125 | void exit_music() { 126 | 127 | ndspChnWaveBufClear(sound[0].audiochannel); 128 | for (int i = 0; i < SOUND_NUMBER; i++) { 129 | ndspChnWaveBufClear(sound[i].audiochannel); 130 | linearFree(sound[i].data); 131 | } 132 | ndspExit(); 133 | } 134 | 135 | int music_SamplePos(int id) { 136 | return (int)ndspChnGetSamplePos(sound[id].audiochannel); 137 | } -------------------------------------------------------------------------------- /source/header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include <3ds.h> 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define VERSION "1.2.0" 15 | #define DEFAULT_DIR "sdmc:/tjafiles/" 16 | #define SETTING_FILE "sdmc:/TJAPlayerfor3ds_setting.json" 17 | #define PATH_DSP1 "sdmc:/3ds/dspfirm.cdc" 18 | #define GENRE_FILE "genre.json" 19 | 20 | #define DEFAULT_JUDGE_RANGE_PERFECT 0.034 21 | #define DEFAULT_JUDGE_RANGE_NICE 0.117 22 | #define DEFAULT_JUDGE_RANGE_BAD 0.150 23 | 24 | #define NOTES_MEASURE_MAX 256 //一小節の最大ノーツ数+1 25 | #define MEASURE_MAX 8192 26 | #define NOTES_AREA 338.0 //ノーツ表示エリアの長さ 27 | #define NOTES_JUDGE_X 93 //判定枠の中心のX座標 28 | #define NOTES_JUDGE_RANGE 327 //判定枠の中心から小節生成位置の距離(右端+20) 29 | 30 | #define TOP_WIDTH 400 31 | #define TOP_HEIGHT 240 32 | #define BOTTOM_WIDTH 320 33 | #define BOTTOM_HEIGHT 240 34 | 35 | #define SPRITES_NUMER 83 36 | 37 | #define NOTES_MAX 512 38 | #define BARLINE_MAX 512 39 | #define ROLL_MAX 512 40 | #define BALLOON_MAX 512 41 | 42 | #define LIST_MAX 16384 //選曲リストの最大数 43 | #define GENRE_MAX 512 //ジャンルの最大数 44 | 45 | #define DEFAULT_BUFFER_SIZE 8192 46 | 47 | enum NOTES_KND { 48 | 49 | NOTES_REST = 0, //休符 50 | NOTES_DON, //ドン 51 | NOTES_KATSU, //カツ 52 | NOTES_BIGDON, //ドン(大) 53 | NOTES_BIGKATSU, //カツ(大) 54 | NOTES_ROLL, //連打開始 55 | NOTES_BIGROLL, //連打(大)開始 56 | NOTES_BALLOON, //風船開始 57 | NOTES_ROLLEND, //連打終了 58 | NOTES_POTATO, //お芋音符開始 59 | NOTES_BIGROLLEND, //大連打終了 60 | NOTES_BALLOONEND, //風船終了 61 | }; 62 | 63 | enum SPRITE_NOTES_KND { //スプライト用 64 | 65 | SPRITE_TOP = 0, 66 | SPRITE_BOTTOM, 67 | SPRITE_DON, 68 | SPRITE_KATSU, 69 | SPRITE_BIG_DON, 70 | SPRITE_BIG_KATSU, 71 | SPRITE_ROLL_START, 72 | SPRITE_ROLL_INT, 73 | SPRITE_ROLL_END, 74 | SPRITE_BIG_ROLL_START, 75 | SPRITE_BIG_ROLL_INT, 76 | SPRITE_BIG_ROLL_END, 77 | SPRITE_BALLOON, 78 | SPRITE_BALLOON_1, 79 | SPRITE_BALLOON_2, 80 | SPRITE_BALLOON_3, 81 | SPRITE_BALLOON_4, 82 | SPRITE_BALLOON_5, 83 | SPRITE_BALLOON_6, 84 | SPRITE_JUDGE_PERFECT, 85 | SPRITE_JUDGE_NICE, 86 | SPRITE_JUDGE_BAD, 87 | SPRITE_JUDGE_CIRCLE, 88 | SPRITE_CHART_NORMAL, 89 | SPRITE_CHART_EXPERT, 90 | SPRITE_CHART_MASTER, 91 | SPRITE_LANE_EXPERT, 92 | SPRITE_LANE_MASTER, 93 | SPRITE_EFFECT_PERFECT, 94 | SPRITE_EFFECT_SPECIAL_PERFECT, 95 | SPRITE_EFFECT_NICE, 96 | SPRITE_EFFECT_SPECIAL_NICE, 97 | SPRITE_SOUL_ON, 98 | SPRITE_SOUL_OFF, 99 | SPRITE_SOUL_EFFECT, 100 | SPRITE_EFFECT_GOGO, 101 | SPRITE_SCORE_0, 102 | SPRITE_SCORE_1, 103 | SPRITE_SCORE_2, 104 | SPRITE_SCORE_3, 105 | SPRITE_SCORE_4, 106 | SPRITE_SCORE_5, 107 | SPRITE_SCORE_6, 108 | SPRITE_SCORE_7, 109 | SPRITE_SCORE_8, 110 | SPRITE_SCORE_9, 111 | SPRITE_COMBO_0, 112 | SPRITE_COMBO_1, 113 | SPRITE_COMBO_2, 114 | SPRITE_COMBO_3, 115 | SPRITE_COMBO_4, 116 | SPRITE_COMBO_5, 117 | SPRITE_COMBO_6, 118 | SPRITE_COMBO_7, 119 | SPRITE_COMBO_8, 120 | SPRITE_COMBO_9, 121 | SPRITE_COMBO_0_RED, 122 | SPRITE_COMBO_1_RED, 123 | SPRITE_COMBO_2_RED, 124 | SPRITE_COMBO_3_RED, 125 | SPRITE_COMBO_4_RED, 126 | SPRITE_COMBO_5_RED, 127 | SPRITE_COMBO_6_RED, 128 | SPRITE_COMBO_7_RED, 129 | SPRITE_COMBO_8_RED, 130 | SPRITE_COMBO_9_RED, 131 | SPRITE_ROLL_0, 132 | SPRITE_ROLL_1, 133 | SPRITE_ROLL_2, 134 | SPRITE_ROLL_3, 135 | SPRITE_ROLL_4, 136 | SPRITE_ROLL_5, 137 | SPRITE_ROLL_6, 138 | SPRITE_ROLL_7, 139 | SPRITE_ROLL_8, 140 | SPRITE_ROLL_9, 141 | SPRITE_ROLL_COUNT, 142 | SPRITE_BALLOON_COUNT, 143 | SPRITE_EMBLEM_EASY, 144 | SPRITE_EMBLEM_NORMAL, 145 | SPRITE_EMBLEM_HARD, 146 | SPRITE_EMBLEM_ONI, 147 | SPRITE_EMBLEM_EDIT, 148 | }; 149 | 150 | enum COMMAND_KND { 151 | 152 | COMMAND_START = 1, 153 | COMMAND_END, 154 | COMMAND_BPMCHANGE, 155 | COMMAND_GOGOSTART, 156 | COMMAND_GOGOEND, 157 | COMMAND_MEASURE, 158 | COMMAND_SCROLL, 159 | COMMAND_DELAY, 160 | COMMAND_SECTION, 161 | COMMAND_BRANCHSTART, 162 | COMMAND_BRANCHEND, 163 | COMMAND_N, 164 | COMMAND_E, 165 | COMMAND_M, 166 | COMMAND_LEVELHOLD, 167 | COMMAND_BMSCROLL, 168 | COMMAND_HBSCROLL, 169 | COMMAND_BARLINEOFF, 170 | COMMAND_BARLINEON, 171 | }; 172 | 173 | enum HEADER_KND { 174 | 175 | HEADER_TITLE, 176 | HEADER_SUBTITLE, 177 | HEADER_BPM, 178 | HEADER_WAVE, 179 | HEADER_OFFSET, 180 | HEADER_BALLOON, 181 | HEADER_SONGVOL, 182 | HEADER_SEVOL, 183 | HEADER_SCOREINIT, 184 | HEADER_SCOREDIFF, 185 | HEADER_COURSE, 186 | HEADER_STYLE, 187 | HEADER_LIFE, 188 | HEADER_DEMOSTART, 189 | HEADER_SIDE, 190 | HEADER_SCOREMODE, 191 | HEADER_TOTAL, 192 | }; 193 | 194 | enum COURSE_KND { 195 | 196 | COURSE_EASY = 0, 197 | COURSE_NORMAL, 198 | COURSE_HARD, 199 | COURSE_ONI, 200 | COURSE_EDIT, 201 | }; 202 | 203 | enum SCENE_STATE { 204 | 205 | SCENE_SELECTLOAD = 0, 206 | SCENE_WARNING = 5, 207 | SCENE_SELECTSONG = 10, 208 | SCENE_MAINLOAD = 50, 209 | SCENE_MAINGAME = 100, 210 | SCENE_RESULT = 110, 211 | }; 212 | 213 | enum SOUND_KND { 214 | 215 | SOUND_DON = 0, 216 | SOUND_KATSU, 217 | SOUND_BALLOONBREAK, 218 | }; 219 | 220 | enum TIME_KND { 221 | 222 | TIME_NOTES = 0, //ノーツが開始(最初の小節が生成)で計測開始,cntはこれに最初にcreate_time加算(マイナス用,通常は0), 223 | TIME_MAINGAME, //メインゲーム,開始時には-1000,1秒後に計測開始,ノーツ・音楽開始にのみ使用 224 | TIME_FPS, //fps計測用 225 | }; 226 | 227 | enum WARNING_KND { 228 | 229 | WARNING_DSP1 = 0, //DSP1未起動 230 | WARNING_WAVE_NO_EXIST, //音楽ファイルが存在しない 231 | WARNING_WAVE_NOT_OGG, //音楽ファイルがOGGファイルじゃない 232 | }; -------------------------------------------------------------------------------- /source/playback.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "header.h" 4 | #include "vorbis.h" 5 | #include "main.h" 6 | #include "select.h" 7 | 8 | #define delete(ptr) \ 9 | free((void*) ptr); ptr = NULL 10 | 11 | static volatile bool stop = true; 12 | 13 | bool togglePlayback(void){ 14 | 15 | bool paused = ndspChnIsPaused(CHANNEL); 16 | ndspChnSetPaused(CHANNEL, !paused); 17 | return !paused; 18 | } 19 | 20 | void stopPlayback(void){ 21 | 22 | stop = true; 23 | } 24 | 25 | bool isPlaying(void){ 26 | 27 | return !stop; 28 | } 29 | 30 | int getFileType(const char *file){ 31 | 32 | FILE* ftest = fopen(file, "rb"); 33 | uint32_t fileSig; 34 | enum file_types file_type = FILE_TYPE_ERROR; 35 | 36 | /* Failure opening file */ 37 | if(ftest == NULL) 38 | return -1; 39 | 40 | if(fread(&fileSig, 4, 1, ftest) == 0) 41 | goto err; 42 | 43 | switch(fileSig){ 44 | 45 | // "RIFF" 46 | case 0x46464952: 47 | if(fseek(ftest, 4, SEEK_CUR) != 0) 48 | break; 49 | 50 | // "WAVE" 51 | // Check required as AVI file format also uses "RIFF". 52 | if(fread(&fileSig, 4, 1, ftest) == 0) 53 | break; 54 | 55 | if(fileSig != 0x45564157) 56 | break; 57 | 58 | file_type = FILE_TYPE_WAV; 59 | break; 60 | 61 | // "fLaC" 62 | case 0x43614c66: 63 | file_type = FILE_TYPE_FLAC; 64 | break; 65 | 66 | // "OggS" 67 | case 0x5367674F: 68 | if(isVorbis(file) == 0) 69 | file_type = FILE_TYPE_VORBIS; 70 | 71 | break; 72 | 73 | default: 74 | 75 | if((fileSig << 16) == 0xFBFF0000 || 76 | (fileSig << 16) == 0xFAFF0000 || 77 | (fileSig << 8) == 0x33444900) 78 | { 79 | file_type = FILE_TYPE_MP3; 80 | break; 81 | } 82 | break; 83 | } 84 | 85 | err: 86 | fclose(ftest); 87 | return file_type; 88 | } 89 | 90 | int testtest = 0; 91 | 92 | void playFile(void* infoIn){ 93 | 94 | struct decoder_fn decoder; 95 | struct playbackInfo_t* info = (playbackInfo_t*)infoIn; 96 | int16_t* buffer1 = NULL; 97 | int16_t* buffer2 = NULL; 98 | ndspWaveBuf waveBuf[2]; 99 | bool lastbuf = false; 100 | int ret = -1; 101 | const char* file = info->file; 102 | bool isNdspInit = false; 103 | 104 | /* Reset previous stop command */ 105 | stop = false; 106 | 107 | switch(getFileType(file)) 108 | { 109 | case FILE_TYPE_VORBIS: 110 | setVorbis(&decoder); 111 | break; 112 | 113 | default: 114 | goto err; 115 | } 116 | 117 | if(ndspInit() < 0) 118 | { 119 | goto err; 120 | } 121 | 122 | isNdspInit = true; 123 | 124 | if((ret = (*decoder.init)(file)) != 0) 125 | { 126 | goto err; 127 | } 128 | 129 | if((*decoder.channels)() > 2 || (*decoder.channels)() < 1) 130 | { 131 | goto err; 132 | } 133 | testtest = 99; 134 | buffer1 = (int16_t*)linearAlloc(decoder.vorbis_buffer_size * sizeof(int16_t)); 135 | buffer2 = (int16_t*)linearAlloc(decoder.vorbis_buffer_size * sizeof(int16_t)); 136 | 137 | ndspChnReset(CHANNEL); 138 | ndspChnWaveBufClear(CHANNEL); 139 | ndspSetOutputMode(NDSP_OUTPUT_STEREO); 140 | ndspChnSetInterp(CHANNEL, NDSP_INTERP_POLYPHASE); 141 | ndspChnSetRate(CHANNEL, (*decoder.rate)()); 142 | ndspChnSetFormat(CHANNEL, 143 | (*decoder.channels)() == 2 ? NDSP_FORMAT_STEREO_PCM16 : 144 | NDSP_FORMAT_MONO_PCM16); 145 | 146 | memset(waveBuf, 0, sizeof(waveBuf)); 147 | 148 | while (*info->isPlay == false) svcSleepThread(100 * 1000); 149 | 150 | waveBuf[0].nsamples = (*decoder.decode)(&buffer1[0]) / (*decoder.channels)(); 151 | waveBuf[0].data_vaddr = &buffer1[0]; 152 | ndspChnWaveBufAdd(CHANNEL, &waveBuf[0]); 153 | 154 | waveBuf[1].nsamples = (*decoder.decode)(&buffer2[0]) / (*decoder.channels)(); 155 | waveBuf[1].data_vaddr = &buffer2[0]; 156 | ndspChnWaveBufAdd(CHANNEL, &waveBuf[1]); 157 | 158 | while(ndspChnIsPlaying(CHANNEL) == false); 159 | 160 | while(stop == false){ 161 | svcSleepThread(100 * 1000); 162 | 163 | if(lastbuf == true && waveBuf[0].status == NDSP_WBUF_DONE && 164 | waveBuf[1].status == NDSP_WBUF_DONE) 165 | break; 166 | 167 | if(ndspChnIsPaused(CHANNEL) == true || lastbuf == true) 168 | continue; 169 | 170 | if(waveBuf[0].status == NDSP_WBUF_DONE){ 171 | 172 | size_t read = (*decoder.decode)(&buffer1[0]); 173 | 174 | if(read <= 0) 175 | { 176 | lastbuf = true; 177 | continue; 178 | } 179 | else if(read < decoder.vorbis_buffer_size) 180 | waveBuf[0].nsamples = read / (*decoder.channels)(); 181 | 182 | ndspChnWaveBufAdd(CHANNEL, &waveBuf[0]); 183 | } 184 | 185 | if(waveBuf[1].status == NDSP_WBUF_DONE) 186 | { 187 | size_t read = (*decoder.decode)(&buffer2[0]); 188 | 189 | if(read <= 0) 190 | { 191 | lastbuf = true; 192 | continue; 193 | } 194 | else if(read < decoder.vorbis_buffer_size) 195 | waveBuf[1].nsamples = read / (*decoder.channels)(); 196 | 197 | ndspChnWaveBufAdd(CHANNEL, &waveBuf[1]); 198 | } 199 | 200 | 201 | //DSP_FlushDataCache(buffer1, decoder.vorbis_buffer_size * sizeof(int16_t)); 202 | //DSP_FlushDataCache(buffer2, decoder.vorbis_buffer_size * sizeof(int16_t)); 203 | } 204 | 205 | (*decoder.exit)(); 206 | out: 207 | if(isNdspInit == true) 208 | { 209 | ndspChnWaveBufClear(CHANNEL); 210 | ndspExit(); 211 | } 212 | 213 | delete(info->file); 214 | linearFree(buffer1); 215 | linearFree(buffer2); 216 | 217 | threadExit(0); 218 | return; 219 | 220 | err: 221 | goto out; 222 | } 223 | 224 | struct playbackInfo_t playbackInfo; 225 | 226 | int changeFile(const char* ep_file, struct playbackInfo_t* playbackInfo, bool *p_isPlayMain){ 227 | 228 | s32 prio; 229 | static Thread thread = NULL; 230 | 231 | if (ep_file != NULL && getFileType(ep_file) == FILE_TYPE_ERROR) return -1; 232 | 233 | if (thread != NULL) { 234 | stopPlayback(); 235 | 236 | threadJoin(thread, U64_MAX); 237 | threadFree(thread); 238 | thread = NULL; 239 | } 240 | 241 | if (ep_file == NULL || playbackInfo == NULL) 242 | return 0; 243 | 244 | playbackInfo->file = strdup(ep_file); 245 | playbackInfo->isPlay = p_isPlayMain; 246 | 247 | svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); 248 | thread = threadCreate(playFile, playbackInfo, 32 * 1024, prio - 1, -2, false); 249 | 250 | return 0; 251 | } 252 | 253 | void play_main_music(bool *p_isPlayMain,LIST_T Song) { 254 | 255 | chdir(Song.path); 256 | changeFile(Song.wave, &playbackInfo, p_isPlayMain); 257 | } 258 | 259 | void pasue_main_music() { 260 | 261 | if (isPlaying() == true) { 262 | togglePlayback(); 263 | } 264 | } 265 | 266 | void stop_main_music() { 267 | 268 | stopPlayback(); 269 | changeFile(NULL, &playbackInfo ,NULL); 270 | } 271 | 272 | void init_main_music() { 273 | 274 | playbackInfo.file = NULL; 275 | } 276 | 277 | int check_wave(LIST_T Song) { //音楽ファイルの確認 278 | 279 | chdir(Song.path); 280 | int result = getFileType(Song.wave); 281 | 282 | if (result == -1) return WARNING_WAVE_NO_EXIST; 283 | else if (result != FILE_TYPE_VORBIS) return WARNING_WAVE_NOT_OGG; 284 | 285 | return -1; 286 | } -------------------------------------------------------------------------------- /resource/app.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : $(APP_TITLE) 3 | ProductCode : $(APP_PRODUCT_CODE) 4 | Logo : Homebrew 5 | 6 | RomFs: 7 | RootPath: $(APP_ROMFS) 8 | 9 | TitleInfo: 10 | Category : Application 11 | UniqueId : $(APP_UNIQUE_ID) 12 | 13 | 14 | Option: 15 | UseOnSD : true # true if App is to be installed to SD 16 | FreeProductCode : true # Removes limitations on ProductCode 17 | MediaFootPadding : false # If true CCI files are created with padding 18 | EnableCrypt : false # Enables encryption for NCCH and CIA 19 | EnableCompress : true # Compresses where applicable (currently only exefs:/.code) 20 | 21 | AccessControlInfo: 22 | CoreVersion : 2 23 | 24 | # Exheader Format Version 25 | DescVersion : 2 26 | 27 | # Minimum Required Kernel Version (below is for 4.5.0) 28 | ReleaseKernelMajor : "02" 29 | ReleaseKernelMinor : "33" 30 | 31 | # ExtData 32 | UseExtSaveData : false # enables ExtData 33 | #ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId 34 | 35 | # FS:USER Archive Access Permissions 36 | # Uncomment as required 37 | FileSystemAccess: 38 | - CategorySystemApplication 39 | - CategoryHardwareCheck 40 | - CategoryFileSystemTool 41 | - Debug 42 | - TwlCardBackup 43 | - TwlNandData 44 | - Boss 45 | - DirectSdmc 46 | - Core 47 | - CtrNandRo 48 | - CtrNandRw 49 | - CtrNandRoWrite 50 | - CategorySystemSettings 51 | - CardBoard 52 | - ExportImportIvs 53 | - DirectSdmcWrite 54 | - SwitchCleanup 55 | - SaveDataMove 56 | - Shop 57 | - Shell 58 | - CategoryHomeMenu 59 | IoAccessControl: 60 | - FsMountNand 61 | - FsMountNandRoWrite 62 | - FsMountTwln 63 | - FsMountWnand 64 | - FsMountCardSpi 65 | - UseSdif3 66 | - CreateSeed 67 | - UseCardSpi 68 | 69 | # Process Settings 70 | MemoryType : Application # Application/System/Base 71 | SystemMode : 64MB # 64MB(Default)/96MB/80MB/72MB/32MB 72 | IdealProcessor : 0 73 | AffinityMask : 1 74 | Priority : 16 75 | MaxCpu : 0xFF 76 | HandleTableSize : 0x200 77 | DisableDebug : false 78 | EnableForceDebug : false 79 | CanWriteSharedPage : true 80 | CanUsePrivilegedPriority : false 81 | CanUseNonAlphabetAndNumber : true 82 | PermitMainFunctionArgument : true 83 | CanShareDeviceMemory : true 84 | RunnableOnSleep : true 85 | SpecialMemoryArrange : true 86 | 87 | # New3DS Exclusive Process Settings 88 | SystemModeExt : 124MB # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode 89 | CpuSpeed : 804MHz # 268MHz(Default)/804MHz 90 | EnableL2Cache : true # false(default)/true 91 | CanAccessCore2 : true 92 | 93 | # Virtual Address Mappings 94 | IORegisterMapping: 95 | - 1ff00000-1ff7ffff # DSP memory 96 | MemoryMapping: 97 | - 1f000000-1f5fffff:r # VRAM 98 | 99 | # Accessible SVCs, : 100 | SystemCallAccess: 101 | ControlMemory: 1 102 | QueryMemory: 2 103 | ExitProcess: 3 104 | GetProcessAffinityMask: 4 105 | SetProcessAffinityMask: 5 106 | GetProcessIdealProcessor: 6 107 | SetProcessIdealProcessor: 7 108 | CreateThread: 8 109 | ExitThread: 9 110 | SleepThread: 10 111 | GetThreadPriority: 11 112 | SetThreadPriority: 12 113 | GetThreadAffinityMask: 13 114 | SetThreadAffinityMask: 14 115 | GetThreadIdealProcessor: 15 116 | SetThreadIdealProcessor: 16 117 | GetCurrentProcessorNumber: 17 118 | Run: 18 119 | CreateMutex: 19 120 | ReleaseMutex: 20 121 | CreateSemaphore: 21 122 | ReleaseSemaphore: 22 123 | CreateEvent: 23 124 | SignalEvent: 24 125 | ClearEvent: 25 126 | CreateTimer: 26 127 | SetTimer: 27 128 | CancelTimer: 28 129 | ClearTimer: 29 130 | CreateMemoryBlock: 30 131 | MapMemoryBlock: 31 132 | UnmapMemoryBlock: 32 133 | CreateAddressArbiter: 33 134 | ArbitrateAddress: 34 135 | CloseHandle: 35 136 | WaitSynchronization1: 36 137 | WaitSynchronizationN: 37 138 | SignalAndWait: 38 139 | DuplicateHandle: 39 140 | GetSystemTick: 40 141 | GetHandleInfo: 41 142 | GetSystemInfo: 42 143 | GetProcessInfo: 43 144 | GetThreadInfo: 44 145 | ConnectToPort: 45 146 | SendSyncRequest1: 46 147 | SendSyncRequest2: 47 148 | SendSyncRequest3: 48 149 | SendSyncRequest4: 49 150 | SendSyncRequest: 50 151 | OpenProcess: 51 152 | OpenThread: 52 153 | GetProcessId: 53 154 | GetProcessIdOfThread: 54 155 | GetThreadId: 55 156 | GetResourceLimit: 56 157 | GetResourceLimitLimitValues: 57 158 | GetResourceLimitCurrentValues: 58 159 | GetThreadContext: 59 160 | Break: 60 161 | OutputDebugString: 61 162 | ControlPerformanceCounter: 62 163 | CreatePort: 71 164 | CreateSessionToPort: 72 165 | CreateSession: 73 166 | AcceptSession: 74 167 | ReplyAndReceive1: 75 168 | ReplyAndReceive2: 76 169 | ReplyAndReceive3: 77 170 | ReplyAndReceive4: 78 171 | ReplyAndReceive: 79 172 | BindInterrupt: 80 173 | UnbindInterrupt: 81 174 | InvalidateProcessDataCache: 82 175 | StoreProcessDataCache: 83 176 | FlushProcessDataCache: 84 177 | StartInterProcessDma: 85 178 | StopDma: 86 179 | GetDmaState: 87 180 | RestartDma: 88 181 | DebugActiveProcess: 96 182 | BreakDebugProcess: 97 183 | TerminateDebugProcess: 98 184 | GetProcessDebugEvent: 99 185 | ContinueDebugEvent: 100 186 | GetProcessList: 101 187 | GetThreadList: 102 188 | GetDebugThreadContext: 103 189 | SetDebugThreadContext: 104 190 | QueryDebugProcessMemory: 105 191 | ReadProcessMemory: 106 192 | WriteProcessMemory: 107 193 | SetHardwareBreakPoint: 108 194 | GetDebugThreadParam: 109 195 | ControlProcessMemory: 112 196 | MapProcessMemory: 113 197 | UnmapProcessMemory: 114 198 | CreateCodeSet: 115 199 | CreateProcess: 117 200 | TerminateProcess: 118 201 | SetProcessResourceLimits: 119 202 | CreateResourceLimit: 120 203 | SetResourceLimitValues: 121 204 | AddCodeSegment: 122 205 | Backdoor: 123 206 | KernelSetState: 124 207 | QueryProcessMemory: 125 208 | 209 | # Service List 210 | # Maximum 34 services (32 if firmware is prior to 9.6.0) 211 | ServiceAccessControl: 212 | - APT:U 213 | - ac:u 214 | - am:net 215 | - boss:U 216 | - cam:u 217 | - cecd:u 218 | - cfg:nor 219 | - cfg:u 220 | - csnd:SND 221 | - dsp::DSP 222 | - frd:u 223 | - fs:USER 224 | - gsp::Gpu 225 | - gsp::Lcd 226 | - hid:USER 227 | - http:C 228 | - ir:rst 229 | - ir:u 230 | - ir:USER 231 | - mic:u 232 | - mcu::HWC 233 | - mvd:STD 234 | - ndm:u 235 | - news:s 236 | - nwm::EXT 237 | - nwm::UDS 238 | - ptm:sysm 239 | - ptm:u 240 | - pxi:dev 241 | - soc:U 242 | - ssl:C 243 | - y2r:u 244 | 245 | 246 | SystemControlInfo: 247 | SaveDataSize: 0KB # Change if the app uses savedata 248 | RemasterVersion: $(APP_VERSION_MAJOR) 249 | StackSize: 0x40000 250 | 251 | # Modules that run services listed above should be included below 252 | # Maximum 48 dependencies 253 | # : 254 | Dependency: 255 | ac: 0x0004013000002402 256 | #act: 0x0004013000003802 257 | am: 0x0004013000001502 258 | boss: 0x0004013000003402 259 | camera: 0x0004013000001602 260 | cecd: 0x0004013000002602 261 | cfg: 0x0004013000001702 262 | codec: 0x0004013000001802 263 | csnd: 0x0004013000002702 264 | dlp: 0x0004013000002802 265 | dsp: 0x0004013000001a02 266 | friends: 0x0004013000003202 267 | gpio: 0x0004013000001b02 268 | gsp: 0x0004013000001c02 269 | hid: 0x0004013000001d02 270 | http: 0x0004013000002902 271 | i2c: 0x0004013000001e02 272 | ir: 0x0004013000003302 273 | mcu: 0x0004013000001f02 274 | mic: 0x0004013000002002 275 | mvd: 0x0004013020004102 276 | ndm: 0x0004013000002b02 277 | news: 0x0004013000003502 278 | #nfc: 0x0004013000004002 279 | nim: 0x0004013000002c02 280 | nwm: 0x0004013000002d02 281 | pdn: 0x0004013000002102 282 | ps: 0x0004013000003102 283 | ptm: 0x0004013000002202 284 | #qtm: 0x0004013020004202 285 | ro: 0x0004013000003702 286 | socket: 0x0004013000002e02 287 | spi: 0x0004013000002302 288 | ssl: 0x0004013000002f02 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITARM)/3ds_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # GRAPHICS is a list of directories containing graphics files 19 | # GFXBUILD is the directory where converted graphics files will be placed 20 | # If set to $(BUILD), it will statically link in the converted 21 | # files as if they were data files. 22 | # 23 | # NO_SMDH: if set to anything, no SMDH file is generated. 24 | # ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional) 25 | # APP_TITLE is the name of the app stored in the SMDH file (Optional) 26 | # APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) 27 | # APP_AUTHOR is the author of the app stored in the SMDH file (Optional) 28 | # ICON is the filename of the icon (.png), relative to the project folder. 29 | # If not set, it attempts to use one of the following (in this order): 30 | # - .png 31 | # - icon.png 32 | # - /default_icon.png 33 | #--------------------------------------------------------------------------------- 34 | TARGET := $(notdir $(CURDIR)) 35 | BUILD := build 36 | SOURCES := source 37 | DATA := data 38 | INCLUDES := include 39 | GRAPHICS := gfx 40 | ROMFS := romfs 41 | GFXBUILD := $(ROMFS)/gfx 42 | #--------------------------------------------------------------------------------- 43 | APP_VER := 1056 #1024.16.1? 44 | APP_TITLE := TJAPlayer for 3DS 45 | APP_DESCRIPTION := TJAPlayer for 3DS - Music game of the TJA file. 46 | APP_AUTHOR := Togetoge 47 | PRODUCT_CODE := CTR-HB-TJAP 48 | UNIQUE_ID := 0xB7655 49 | 50 | BANNER_AUDIO := resource/banner.wav 51 | BANNER_IMAGE := resource/banner.cgfx 52 | ICON := resource/icon.png 53 | RSF_PATH := resource/app.rsf 54 | 55 | #--------------------------------------------------------------------------------- 56 | #--------------------------------------------------------------------------------- 57 | # options for code generation 58 | #--------------------------------------------------------------------------------- 59 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft 60 | 61 | CFLAGS := -g -Wall -O2 -mword-relocations \ 62 | -fomit-frame-pointer -ffunction-sections \ 63 | $(ARCH) 64 | 65 | CFLAGS += $(INCLUDE) -DARM11 -D_3DS 66 | 67 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 68 | 69 | ASFLAGS := -g $(ARCH) 70 | LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 71 | 72 | LIBS := -lcitro2d -lcitro3d -lctru -lm -lvorbisidec -logg -ljansson 73 | 74 | #--------------------------------------------------------------------------------- 75 | # list of directories containing libraries, this must be the top level containing 76 | # include and lib 77 | #--------------------------------------------------------------------------------- 78 | LIBDIRS := $(CTRULIB) $(PORTLIBS) 79 | 80 | #--------------------------------------------------------------------------------- 81 | # no real need to edit anything past this point unless you need to add additional 82 | # rules for different file extensions 83 | #--------------------------------------------------------------------------------- 84 | ifneq ($(BUILD),$(notdir $(CURDIR))) 85 | #--------------------------------------------------------------------------------- 86 | 87 | export OUTPUT := $(CURDIR)/$(TARGET) 88 | export TOPDIR := $(CURDIR) 89 | 90 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 91 | $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) \ 92 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 93 | 94 | export DEPSDIR := $(CURDIR)/$(BUILD) 95 | 96 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 97 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 98 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 99 | PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica))) 100 | SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist))) 101 | GFXFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.t3s))) 102 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 103 | 104 | #--------------------------------------------------------------------------------- 105 | # use CXX for linking C++ projects, CC for standard C 106 | #--------------------------------------------------------------------------------- 107 | ifeq ($(strip $(CPPFILES)),) 108 | #--------------------------------------------------------------------------------- 109 | export LD := $(CC) 110 | #--------------------------------------------------------------------------------- 111 | else 112 | #--------------------------------------------------------------------------------- 113 | export LD := $(CXX) 114 | #--------------------------------------------------------------------------------- 115 | endif 116 | #--------------------------------------------------------------------------------- 117 | 118 | #--------------------------------------------------------------------------------- 119 | ifeq ($(GFXBUILD),$(BUILD)) 120 | #--------------------------------------------------------------------------------- 121 | export T3XFILES := $(GFXFILES:.t3s=.t3x) 122 | #--------------------------------------------------------------------------------- 123 | else 124 | #--------------------------------------------------------------------------------- 125 | export ROMFS_T3XFILES := $(patsubst %.t3s, $(GFXBUILD)/%.t3x, $(GFXFILES)) 126 | export T3XHFILES := $(patsubst %.t3s, $(BUILD)/%.h, $(GFXFILES)) 127 | #--------------------------------------------------------------------------------- 128 | endif 129 | #--------------------------------------------------------------------------------- 130 | 131 | export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 132 | 133 | export OFILES_BIN := $(addsuffix .o,$(BINFILES)) \ 134 | $(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \ 135 | $(addsuffix .o,$(T3XFILES)) 136 | 137 | export OFILES := $(OFILES_BIN) $(OFILES_SOURCES) 138 | 139 | export HFILES := $(PICAFILES:.v.pica=_shbin.h) $(SHLISTFILES:.shlist=_shbin.h) \ 140 | $(addsuffix .h,$(subst .,_,$(BINFILES))) \ 141 | $(GFXFILES:.t3s=.h) 142 | 143 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 144 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 145 | -I$(CURDIR)/$(BUILD) 146 | 147 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 148 | 149 | export _3DSXDEPS := $(if $(NO_SMDH),,$(OUTPUT).smdh) 150 | 151 | ifeq ($(strip $(ICON)),) 152 | icons := $(wildcard *.png) 153 | ifneq (,$(findstring $(TARGET).png,$(icons))) 154 | export APP_ICON := $(TOPDIR)/$(TARGET).png 155 | else 156 | ifneq (,$(findstring icon.png,$(icons))) 157 | export APP_ICON := $(TOPDIR)/icon.png 158 | endif 159 | endif 160 | else 161 | export APP_ICON := $(TOPDIR)/$(ICON) 162 | endif 163 | 164 | ifeq ($(strip $(NO_SMDH)),) 165 | export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh 166 | endif 167 | 168 | ifneq ($(ROMFS),) 169 | export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS) 170 | endif 171 | 172 | .PHONY: all clean 173 | 174 | #--------------------------------------------------------------------------------- 175 | MAKEROM ?= makerom 176 | MAKEROM_ARGS := -elf "$(OUTPUT).elf" -rsf "$(RSF_PATH)" -banner "$(BUILD)/banner.bnr" -icon "$(BUILD)/icon.icn" -DAPP_TITLE="$(APP_TITLE)" -DAPP_PRODUCT_CODE="$(PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(UNIQUE_ID)" 177 | 178 | ifneq ($(strip $(LOGO)),) 179 | MAKEROM_ARGS += -logo "$(LOGO)" 180 | endif 181 | ifneq ($(strip $(ROMFS)),) 182 | MAKEROM_ARGS += -DAPP_ROMFS="$(ROMFS)" 183 | endif 184 | 185 | BANNERTOOL ?= bannertool 186 | 187 | ifeq ($(suffix $(BANNER_IMAGE)),.cgfx) 188 | BANNER_IMAGE_ARG := -ci 189 | else 190 | BANNER_IMAGE_ARG := -i 191 | endif 192 | 193 | ifeq ($(suffix $(BANNER_AUDIO)),.cwav) 194 | BANNER_AUDIO_ARG := -ca 195 | else 196 | BANNER_AUDIO_ARG := -a 197 | endif 198 | # 199 | 200 | #--------------------------------------------------------------------------------- 201 | 202 | all: $(BUILD) $(GFXBUILD) $(DEPSDIR) $(ROMFS_T3XFILES) $(T3XHFILES) 203 | @echo Building 3dsx... 204 | @$(MAKE) -j -s --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 205 | @echo 206 | @echo Building cia... 207 | @$(BANNERTOOL) makebanner $(BANNER_IMAGE_ARG) $(BANNER_IMAGE) $(BANNER_AUDIO_ARG) $(BANNER_AUDIO) -o $(BUILD)/banner.bnr 208 | @$(BANNERTOOL) makesmdh -s "$(APP_TITLE)" -l "$(APP_DESCRIPTION)" -p $(APP_AUTHOR) -i $(APP_ICON) -o $(BUILD)/icon.icn 209 | @$(MAKEROM) -f cia -o $(OUTPUT).cia -target t -exefslogo $(MAKEROM_ARGS) -ver $(APP_VER) 210 | 211 | #--------------------------------------------------------------------------------- 212 | 3dsx: $(BUILD) $(GFXBUILD) $(DEPSDIR) $(ROMFS_T3XFILES) $(T3XHFILES) 213 | @echo Building 3dsx... 214 | @$(MAKE) -j -s --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 215 | 216 | $(BUILD): 217 | @mkdir -p $@ 218 | 219 | ifneq ($(GFXBUILD),$(BUILD)) 220 | $(GFXBUILD): 221 | @mkdir -p $@ 222 | endif 223 | 224 | ifneq ($(DEPSDIR),$(BUILD)) 225 | $(DEPSDIR): 226 | @mkdir -p $@ 227 | endif 228 | 229 | 230 | #--------------------------------------------------------------------------------- 231 | clean: 232 | @echo clean ... 233 | @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf $(TARGET).cia $(GFXBUILD) 234 | 235 | #--------------------------------------------------------------------------------- 236 | $(GFXBUILD)/%.t3x $(BUILD)/%.h : %.t3s 237 | #--------------------------------------------------------------------------------- 238 | @echo $(notdir $<) 239 | @tex3ds -i $< -H $(BUILD)/$*.h -d $(DEPSDIR)/$*.d -o $(GFXBUILD)/$*.t3x 240 | 241 | #--------------------------------------------------------------------------------- 242 | else 243 | 244 | #--------------------------------------------------------------------------------- 245 | # main targets 246 | #--------------------------------------------------------------------------------- 247 | $(OUTPUT).3dsx : $(OUTPUT).elf $(_3DSXDEPS) 248 | 249 | $(OFILES_SOURCES) : $(HFILES) 250 | 251 | $(OUTPUT).elf : $(OFILES) 252 | 253 | #--------------------------------------------------------------------------------- 254 | # you need a rule like this for each extension you use as binary data 255 | #--------------------------------------------------------------------------------- 256 | %.bin.o %_bin.h : %.bin 257 | #--------------------------------------------------------------------------------- 258 | @echo $(notdir $<) 259 | @$(bin2o) 260 | 261 | #--------------------------------------------------------------------------------- 262 | .PRECIOUS : %.t3x 263 | #--------------------------------------------------------------------------------- 264 | %.t3x.o %_t3x.h : %.t3x 265 | #--------------------------------------------------------------------------------- 266 | @echo $(notdir $<) 267 | @$(bin2o) 268 | 269 | #--------------------------------------------------------------------------------- 270 | # rules for assembling GPU shaders 271 | #--------------------------------------------------------------------------------- 272 | define shader-as 273 | $(eval CURBIN := $*.shbin) 274 | $(eval DEPSFILE := $(DEPSDIR)/$*.shbin.d) 275 | echo "$(CURBIN).o: $< $1" > $(DEPSFILE) 276 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h 277 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h 278 | echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h 279 | picasso -o $(CURBIN) $1 280 | bin2s $(CURBIN) | $(AS) -o $*.shbin.o 281 | endef 282 | 283 | %.shbin.o %_shbin.h : %.v.pica %.g.pica 284 | @echo $(notdir $^) 285 | @$(call shader-as,$^) 286 | 287 | %.shbin.o %_shbin.h : %.v.pica 288 | @echo $(notdir $<) 289 | @$(call shader-as,$<) 290 | 291 | %.shbin.o %_shbin.h : %.shlist 292 | @echo $(notdir $<) 293 | @$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)$(file))) 294 | 295 | #--------------------------------------------------------------------------------- 296 | %.t3x %.h : %.t3s 297 | #--------------------------------------------------------------------------------- 298 | @echo $(notdir $<) 299 | @tex3ds -i $< -H $*.h -d $*.d -o $*.t3x 300 | 301 | -include $(DEPSDIR)/*.d 302 | 303 | #--------------------------------------------------------------------------------------- 304 | endif 305 | #--------------------------------------------------------------------------------------- 306 | -------------------------------------------------------------------------------- /source/select.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "main.h" 3 | #include "select.h" 4 | #include "tja.h" 5 | #include "audio.h" 6 | #include "notes.h" 7 | #include "option.h" 8 | #include 9 | #include 10 | #include 11 | 12 | void load_file_list(const char* path); 13 | void set_genres(); 14 | 15 | LIST_T List[LIST_MAX]; 16 | GENRE_T Genre[GENRE_MAX]; 17 | char buf_select[256]; 18 | int SongNumber = 0; //曲の総数 19 | int GenreNumber = 0; //ジャンルの総数 20 | int ClosedSongNumber = 0; //閉じたジャンル内の曲数 21 | int GenreCount = 0, SongCount = 0, cursor = 0, course_cursor = 0, course_count = 0, SelectedId = 0, SelectedGenreId = 0 ,course = COURSE_ONI; 22 | bool isSelectCourse = false, isCursorGenre = false, isGameStart = false; 23 | 24 | int cmp_list(const void* p, const void* q) { //比較用 25 | 26 | int pp = ((LIST_T*)p)->genre; 27 | int qq = ((LIST_T*)q)->genre; 28 | 29 | return pp - qq; 30 | } 31 | 32 | void sort_list() { //曲をジャンル順にソート 33 | 34 | qsort(List, SongNumber, sizeof(LIST_T), cmp_list); 35 | } 36 | 37 | void load_file_main() { 38 | 39 | chdir(DEFAULT_DIR); 40 | load_file_list(DEFAULT_DIR); 41 | SongNumber = SongCount; 42 | GenreNumber = GenreCount; 43 | set_genres(); 44 | sort_list(); 45 | } 46 | 47 | void load_genre_file(int id) { 48 | 49 | json_t* json; 50 | json_error_t error_json; 51 | char tmp[256]; 52 | 53 | chdir(Genre[id].path); 54 | json = json_load_file(GENRE_FILE, 0, &error_json); 55 | 56 | strlcpy(Genre[id].name, "Genre", 256); 57 | Genre[id].genre_color = 0x111111; 58 | Genre[id].font_color = 0xffffff; 59 | 60 | if (json != NULL) { 61 | 62 | Genre[id].isOpened = false; 63 | strlcpy(Genre[id].name, json_string_value(json_object_get(json, "GenreName")), sizeof(Genre[id].name)); 64 | strlcpy(tmp, json_string_value(json_object_get(json, "GenreColor")), sizeof(tmp)); 65 | if (tmp[0] == '#') tmp[0] = ' '; 66 | Genre[id].genre_color = strtol(tmp, NULL, 16); 67 | strlcpy(tmp, json_string_value(json_object_get(json, "FontColor")), sizeof(tmp)); 68 | if (tmp[0] == '#') tmp[0] = ' '; 69 | Genre[id].font_color = strtol(tmp, NULL, 16); 70 | } 71 | if (json == NULL) { //開けなかった時 72 | } 73 | 74 | json_decref(json); 75 | } 76 | 77 | void load_file_list(const char* path) { 78 | 79 | DIR* dir; 80 | struct dirent* dp; 81 | 82 | if ((dir = opendir(path)) != NULL) { 83 | 84 | DIR* db; 85 | char filename[512]; 86 | while ((dp = readdir(dir)) != NULL) { 87 | 88 | chdir(path); 89 | 90 | strlcpy(filename, path, strlen(path)); 91 | strcat(filename, "/"); 92 | strcat(filename, dp->d_name); 93 | 94 | db = opendir(filename); 95 | 96 | struct stat st; 97 | stat(dp->d_name, &st); 98 | 99 | if ((st.st_mode & S_IFMT) != S_IFDIR) { 100 | 101 | if (db == NULL) { 102 | 103 | if (strstr(dp->d_name, ".tja") != NULL) { 104 | 105 | strlcpy(List[SongCount].tja, dp->d_name, strlen(dp->d_name) + 1); 106 | getcwd(List[SongCount].path, 256); 107 | List[SongCount].genre = GENRE_MAX + 1; 108 | load_tja_head_simple(&List[SongCount]); 109 | SongCount++; 110 | } 111 | 112 | if (strstr(dp->d_name, GENRE_FILE) != NULL) { 113 | 114 | getcwd(Genre[GenreCount].path, 256); 115 | load_genre_file(GenreCount); 116 | GenreCount++; 117 | } 118 | } 119 | } 120 | else { 121 | load_file_list(dp->d_name); 122 | chdir("../"); 123 | } 124 | closedir(db); 125 | } 126 | } 127 | closedir(dir); 128 | } 129 | 130 | void set_genres() { 131 | 132 | for (int i = 0; i < GenreNumber; i++) { 133 | 134 | for (int j = 0; j < SongNumber; j++) { 135 | 136 | if (strstr(List[j].path, Genre[i].path) != NULL) List[j].genre = i; 137 | } 138 | } 139 | } 140 | 141 | void draw_select_box(float x,float y,float w,float h,int color= 0x424242) { 142 | 143 | float r = ((color >> 16) & 0xFF) / 255.0; 144 | float g = ((color >> 8) & 0xFF) / 255.0; 145 | float b = ((color >> 0) & 0xFF) / 255.0; 146 | C2D_DrawRectangle(x, y, 0, w, h, C2D_Color32f(r, g, b, 1), C2D_Color32f(r, g, b, 1), C2D_Color32f(r, g, b, 1), C2D_Color32f(r, g, b, 1)); 147 | } 148 | 149 | 150 | 151 | void disp_file_list() { 152 | 153 | int n = 0, g = 0; //コース用調整、ジャンル用調整 154 | bool isGenre = false; 155 | course_count = 0; 156 | 157 | if (cursor > 0) cursor = -1 * (SongNumber + GenreNumber - ClosedSongNumber - 1); 158 | if (cursor < -1 * (SongNumber + GenreNumber - ClosedSongNumber- 1)) cursor = 0; 159 | 160 | ClosedSongNumber = 0; 161 | 162 | for (int i = 0; i < SongNumber; i++) { 163 | 164 | isGenre = false; 165 | 166 | if (List[i].genre != GENRE_MAX + 1 && (i == 0 || List[i].genre != List[i - 1].genre)) { //ジャンルの最初の曲 167 | 168 | g++; 169 | isGenre = true; 170 | } 171 | 172 | 173 | if ((n + g + cursor) * 20 + 60 >= 0 && (n + g + cursor) * 20 + 60 <= TOP_HEIGHT) { 174 | 175 | if (isGenre == true) { 176 | 177 | draw_select_box(30, (n + g + cursor - 1) * 20 + 60-3,320,20, Genre[List[i].genre].genre_color); 178 | snprintf(buf_select, sizeof(buf_select), "%s", Genre[List[i].genre].name); 179 | draw_select_text(30, (n + g + cursor - 1) * 20 + 60, buf_select,Genre[List[i].genre].font_color); 180 | 181 | if (n + g -1== (cursor * -1)) { 182 | 183 | SelectedGenreId = List[i].genre; 184 | isCursorGenre = true; 185 | } 186 | } 187 | 188 | if (List[i].genre == GENRE_MAX + 1 || (List[i].genre != GENRE_MAX + 1 && Genre[List[i].genre].isOpened == true)) { 189 | 190 | snprintf(buf_select, sizeof(buf_select), "%s", List[i].title); 191 | int x = (List[i].genre != GENRE_MAX + 1) * 25 + 30; 192 | draw_select_text(x, (n + g + cursor) * 20 + 60, buf_select); 193 | 194 | if (i + g != (cursor * -1)) { 195 | snprintf(buf_select, sizeof(buf_select), "★x%d", List[i].level[COURSE_ONI]); 196 | draw_select_text(360, (n + g + cursor) * 20 + 60, buf_select); 197 | } 198 | } 199 | } 200 | 201 | if (List[i].genre != GENRE_MAX + 1 && Genre[List[i].genre].isOpened == false) { 202 | 203 | ClosedSongNumber++; 204 | continue; 205 | } 206 | 207 | n++; 208 | 209 | if (n + g-1 == (cursor * -1)) { 210 | 211 | SelectedId = i; 212 | int level; 213 | isCursorGenre = false; 214 | 215 | if (List[i].course[COURSE_EDIT] == true) { 216 | 217 | if ((n + g + cursor - 1) == course_cursor) course = COURSE_EDIT; 218 | level = List[i].level[COURSE_EDIT]; 219 | if (level > 10) level = 10; 220 | for (int j = 0; j < level; j++) { 221 | draw_select_text(200 + j * 10, (n + g + cursor) * 20 + 60, "★"); 222 | } 223 | for (int j = 0; j < (10 - level); j++) { 224 | draw_select_text(200 + (j + level) * 10, (n + g + cursor) * 20 + 60, "・"); 225 | } 226 | draw_select_text(80, (n + g + cursor) * 20 + 60, Text[get_lang()][TEXT_ONI]); 227 | snprintf(buf_select, sizeof(buf_select), "★x%d", List[i].level[COURSE_EDIT]); 228 | draw_select_text(360, (n + g + cursor) * 20 + 60, buf_select); 229 | n++; 230 | course_count++; 231 | } 232 | 233 | if (List[i].course[COURSE_ONI] == true) { 234 | 235 | if ((n + g + cursor - 1) == course_cursor) course = COURSE_ONI; 236 | level = List[i].level[COURSE_ONI]; 237 | if (level > 10) level = 10; 238 | for (int j = 0; j < level; j++) { 239 | draw_select_text(200 + j * 10, (n + g + cursor) * 20 + 60, "★"); 240 | } 241 | for (int j = 0; j < (10 - level); j++) { 242 | draw_select_text(200 + (j + level) * 10, (n + g + cursor) * 20 + 60, "・"); 243 | } 244 | draw_select_text(80, (n + g + cursor) * 20 + 60, Text[get_lang()][TEXT_ONI]); 245 | snprintf(buf_select, sizeof(buf_select), "★x%d", List[i].level[COURSE_ONI]); 246 | draw_select_text(360, (n + g + cursor) * 20 + 60, buf_select); 247 | n++; 248 | course_count++; 249 | } 250 | 251 | if (List[i].course[COURSE_HARD] == true) { 252 | 253 | if ((n + g + cursor - 1) == course_cursor) course = COURSE_HARD; 254 | level = List[i].level[COURSE_HARD]; 255 | if (level > 10) level = 10; 256 | for (int j = 0; j < level; j++) { 257 | draw_select_text(200 + j * 10, (n + g + cursor) * 20 + 60, "★"); 258 | } 259 | for (int j = 0; j < (10 - level); j++) { 260 | draw_select_text(200 + (j + level) * 10, (n + g + cursor) * 20 + 60, "・"); 261 | } 262 | draw_select_text(80, (n + g + cursor) * 20 + 60, Text[get_lang()][TEXT_HARD]); 263 | snprintf(buf_select, sizeof(buf_select), "★x%d", List[i].level[COURSE_HARD]); 264 | draw_select_text(360, (n + g + cursor) * 20 + 60, buf_select); 265 | n++; 266 | course_count++; 267 | } 268 | 269 | if (List[i].course[COURSE_NORMAL] == true) { 270 | 271 | if ((n + g + cursor - 1) == course_cursor) course = COURSE_NORMAL; 272 | level = List[i].level[COURSE_NORMAL]; 273 | if (level > 10) level = 10; 274 | for (int j = 0; j < level; j++) { 275 | draw_select_text(200 + j * 10, (n + g + cursor) * 20 + 60, "★"); 276 | } 277 | for (int j = 0; j < (10 - level); j++) { 278 | draw_select_text(200 + (j + level) * 10, (n + g + cursor) * 20 + 60, "・"); 279 | } 280 | draw_select_text(80, (n + g + cursor) * 20 + 60, Text[get_lang()][TEXT_NORMAL]); 281 | snprintf(buf_select, sizeof(buf_select), "★x%d", List[i].level[COURSE_NORMAL]); 282 | draw_select_text(360, (n + g + cursor) * 20 + 60, buf_select); 283 | n++; 284 | course_count++; 285 | } 286 | 287 | if (List[i].course[COURSE_EASY] == true) { 288 | 289 | if ((n + g + cursor - 1) == course_cursor) course = COURSE_EASY; 290 | level = List[i].level[COURSE_EASY]; 291 | if (level > 10) level = 10; 292 | for (int j = 0; j < level; j++) { 293 | draw_select_text(200 + j * 10, (n + g + cursor) * 20 + 60, "★"); 294 | } 295 | for (int j = 0; j < (10 - level); j++) { 296 | draw_select_text(200 + (j + level) * 10, (n + g + cursor) * 20 + 60, "・"); 297 | } 298 | draw_select_text(80, (n + g + cursor) * 20 + 60, Text[get_lang()][TEXT_EASY]); 299 | snprintf(buf_select, sizeof(buf_select), "★x%d", List[i].level[COURSE_EASY]); 300 | draw_select_text(360, (n + g + cursor) * 20 + 60, buf_select); 301 | n++; 302 | course_count++; 303 | } 304 | 305 | if (isSelectCourse == true) { 306 | 307 | draw_select_text(60, (course_cursor + 1) * 20 + 60, ">>"); 308 | //snprintf(buf_select, sizeof(buf_select), "%d",course_cursor); 309 | //draw_select_text(60, (course_cursor + 1) * 20 + 60, buf_select); 310 | } 311 | } 312 | } 313 | 314 | draw_select_text(10, 60, ">>"); 315 | //snprintf(buf_select, sizeof(buf_select), "isCS:%d SI:%d SGI:%dGf:%d",isCursorGenre,SelectedId, SelectedGenreId,Genre[SelectedGenreId].flag); 316 | //draw_select_text(0, 50, buf_select); 317 | 318 | } 319 | 320 | void update_cursor(int knd) { 321 | 322 | if (knd == KEY_UP) { 323 | if (isSelectCourse == false) cursor++; 324 | else if (course_cursor > 0) course_cursor--; 325 | play_sound(SOUND_KATSU); 326 | } 327 | else if (knd == (int)KEY_DOWN) { 328 | if (isSelectCourse == false) cursor--; 329 | else if (course_cursor < (course_count - 1)) course_cursor++; 330 | play_sound(SOUND_KATSU); 331 | } 332 | else if (knd == KEY_RIGHT) { 333 | if (isSelectCourse == false) cursor -= 5; 334 | play_sound(SOUND_KATSU); 335 | } 336 | else if (knd == KEY_LEFT) { 337 | if (isSelectCourse == false) cursor += 5; 338 | play_sound(SOUND_KATSU); 339 | } 340 | else if (knd == KEY_A && (course_count != 0 || isCursorGenre == true)) { 341 | if (isCursorGenre == true) Genre[SelectedGenreId].isOpened = !Genre[SelectedGenreId].isOpened; 342 | else if (isSelectCourse == true) isGameStart = true; 343 | else isSelectCourse = true; 344 | play_sound(SOUND_DON); 345 | } 346 | else if (knd == KEY_B) { 347 | isSelectCourse = false; 348 | course_cursor = 0; 349 | play_sound(SOUND_KATSU); 350 | } 351 | 352 | } 353 | 354 | C2D_TextBuf g_SelectText = C2D_TextBufNew(4096); 355 | C2D_Text SelectText; 356 | 357 | void draw_select_text(float x, float y, const char* text,int color) { //color省略可(0xffffff) 358 | 359 | C2D_TextBufClear(g_SelectText); 360 | C2D_TextParse(&SelectText, g_SelectText, text); 361 | C2D_TextOptimize(&SelectText); 362 | float r = ((color >> 16) & 0xFF)/255.0; 363 | float g = ((color >> 8) & 0xFF)/255.0; 364 | float b = ((color >> 0) & 0xFF)/255.0; 365 | C2D_DrawText(&SelectText, C2D_WithColor, x, y, 1.0f, 0.5f, 0.5f, C2D_Color32f(r, g, b, 1.0f)); 366 | } 367 | 368 | void draw_result_text(float x, float y, float size, const char* text) { 369 | 370 | C2D_TextBufClear(g_SelectText); 371 | C2D_TextParse(&SelectText, g_SelectText, text); 372 | C2D_TextOptimize(&SelectText); 373 | C2D_DrawText(&SelectText, C2D_WithColor, x, y, 0.5f, size, size, C2D_Color32f(1.0f, 1.0f, 1.0f, 1.0f)); 374 | } 375 | 376 | void calc_result_text(const char* text, float* width, float* height) { 377 | 378 | C2D_TextBufClear(g_SelectText); 379 | C2D_TextParse(&SelectText, g_SelectText, text); 380 | C2D_TextOptimize(&SelectText); 381 | float size = 0.7; 382 | C2D_TextGetDimensions(&SelectText, size, size, width, height); 383 | } 384 | 385 | void draw_option_text(float x, float y, const char* text, bool state, float* width, float* height, float sizex, float sizey) { //size省略可(0.7) 386 | 387 | C2D_TextBufClear(g_SelectText); 388 | C2D_TextParse(&SelectText, g_SelectText, text); 389 | C2D_TextOptimize(&SelectText); 390 | C2D_TextGetDimensions(&SelectText, sizex, sizey, width, height); 391 | 392 | if (x == -1) x = BOTTOM_WIDTH / 2 - *width / 2; 393 | 394 | if (state == false) { 395 | C2D_DrawText(&SelectText, C2D_WithColor, x, y, 1.0f, sizex, sizey, C2D_Color32f(100.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0, 1.0f)); 396 | } 397 | else if (state == true) { 398 | C2D_DrawText(&SelectText, C2D_WithColor, x, y, 1.0f, sizex, sizey, C2D_Color32f(1.0f, 1.0f, 1.0f, 1.0f)); 399 | } 400 | 401 | } 402 | 403 | void get_SelectedId(LIST_T* TMP, int* arg) { 404 | 405 | for (int i = 0; i < 5; i++) { 406 | TMP->course[i] = List[SelectedId].course[i]; 407 | TMP->course_exist[i] = List[SelectedId].course_exist[i]; 408 | TMP->level[i] = List[SelectedId].level[i]; 409 | } 410 | strlcpy(TMP->tja, List[SelectedId].tja, strlen(List[SelectedId].tja) + 1); 411 | strlcpy(TMP->path, List[SelectedId].path, strlen(List[SelectedId].path) + 1); 412 | strlcpy(TMP->title, List[SelectedId].title, strlen(List[SelectedId].title) + 1); 413 | strlcpy(TMP->wave, List[SelectedId].wave, strlen(List[SelectedId].wave) + 1); 414 | *arg = course; 415 | } 416 | 417 | bool get_isGameStart() { 418 | return isGameStart; 419 | } 420 | 421 | void select_ini() { 422 | //cursor = 0; 423 | course_cursor = 0; 424 | course_count = 0; 425 | SelectedId = 0; 426 | SelectedGenreId = 0; 427 | course = COURSE_ONI; 428 | isSelectCourse = false; 429 | isCursorGenre = false; 430 | isGameStart = false; 431 | } -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "time.h" 3 | #include "notes.h" 4 | #include "tja.h" 5 | #include "audio.h" 6 | #include "playback.h" 7 | #include "score.h" 8 | #include "select.h" 9 | #include "option.h" 10 | #include "result.h" 11 | #include "main.h" 12 | #include "vorbis.h" 13 | 14 | C2D_Sprite sprites[SPRITES_NUMER]; //画像用 15 | static C2D_SpriteSheet spriteSheet; 16 | C2D_TextBuf g_dynamicBuf; 17 | C2D_Text dynText; 18 | bool isPause = false, isNotesStart = false, isMusicStart = false, isPlayMain = false, isExit = false; 19 | char buffer[BUFFER_SIZE]; 20 | 21 | void load_sprites(); 22 | 23 | void draw_debug(float x, float y, const char *text) { 24 | 25 | //使用例 26 | //snprintf(get_buffer(), BUFFER_SIZE, "%d", 10); 27 | // draw_debug(300, 0, get_buffer()); 28 | 29 | C2D_TextBufClear(g_dynamicBuf); 30 | C2D_TextParse(&dynText, g_dynamicBuf, text); 31 | C2D_TextOptimize(&dynText); 32 | C2D_DrawText(&dynText, C2D_WithColor, x, y, 0.5f, 0.5f, 0.5f, C2D_Color32f(0.0f, 1.0f, 0.0f, 1.0f)); 33 | } 34 | 35 | void init_main() { 36 | 37 | romfsInit(); 38 | gfxInitDefault(); 39 | C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); 40 | C2D_Init(C2D_DEFAULT_MAX_OBJECTS); 41 | C2D_Prepare(); 42 | g_dynamicBuf = C2D_TextBufNew(4096); 43 | } 44 | 45 | void exit_main() { 46 | 47 | C2D_TextBufDelete(g_dynamicBuf); 48 | 49 | C2D_Fini(); 50 | C3D_Fini(); 51 | gfxExit(); 52 | romfsExit(); 53 | exit_music(); 54 | exit_option(); 55 | } 56 | 57 | void button_game(bool *isDon,bool *isKatsu,OPTION_T Option, unsigned int key) { 58 | 59 | int numKeys = 20; 60 | 61 | int Optionkeys[] = { 62 | Option.KEY_A,Option.KEY_B,Option.KEY_X,Option.KEY_Y,Option.KEY_R,Option.KEY_ZR,Option.KEY_L,Option.KEY_ZL,Option.KEY_DUP,Option.KEY_DDOWN,Option.KEY_DRIGHT,Option.KEY_DLEFT, 63 | Option.KEY_CPAD_UP,Option.KEY_CPAD_DOWN,Option.KEY_CPAD_RIGHT,Option.KEY_CPAD_LEFT,Option.KEY_CSTICK_UP,Option.KEY_CSTICK_DOWN,Option.KEY_CSTICK_RIGHT,Option.KEY_CSTICK_LEFT }; 64 | unsigned int keys[] = { 65 | KEY_A,KEY_B,KEY_X,KEY_Y,KEY_R,KEY_ZR,KEY_L,KEY_ZL,KEY_DUP,KEY_DDOWN,KEY_DRIGHT,KEY_DLEFT, 66 | KEY_CPAD_UP,KEY_CPAD_DOWN,KEY_CPAD_RIGHT,KEY_CPAD_LEFT,KEY_CSTICK_UP,KEY_CSTICK_DOWN,KEY_CSTICK_RIGHT,KEY_CSTICK_LEFT}; 67 | 68 | for (int i = 0; i < numKeys;i++) { 69 | if (key & keys[i]) { 70 | if (Optionkeys[i] == KEY_DON) *isDon = true; 71 | else if (Optionkeys[i] == KEY_KATSU) *isKatsu = true; 72 | } 73 | } 74 | } 75 | 76 | bool check_dsp1() { //DSP1を起動しているか確認 77 | 78 | FILE* fp = fopen(PATH_DSP1, "r"); 79 | 80 | if (fp == NULL) return false; 81 | fclose(fp); 82 | 83 | return true; 84 | } 85 | 86 | int touch_x, touch_y, touch_cnt,PreTouch_x,PreTouch_y; //タッチ用 87 | 88 | int main() { 89 | 90 | init_main(); 91 | 92 | touchPosition tp; //下画面タッチした座標 93 | 94 | C3D_RenderTarget* top = C2D_CreateScreenTarget(GFX_TOP, GFX_LEFT); 95 | C3D_RenderTarget* bottom = C2D_CreateScreenTarget(GFX_BOTTOM, GFX_LEFT); 96 | 97 | TJA_HEADER_T TJA_Header; 98 | LIST_T SelectedSong; 99 | OPTION_T Option; 100 | 101 | int cnt = 0, notes_cnt = 0, scene_state = SCENE_SELECTLOAD,warning=-1, course = COURSE_ONI, tmp=0; 102 | 103 | double FirstMeasureTime = INT_MAX, 104 | offset = 0,CurrentTimeMain = -1000; 105 | 106 | while (aptMainLoop()) { 107 | 108 | hidScanInput(); 109 | hidTouchRead(&tp); 110 | unsigned int key = hidKeysDown(); 111 | 112 | if (isExit == true) break; 113 | 114 | bool isDon = false, isKatsu = false; 115 | 116 | C3D_FrameBegin(C3D_FRAME_SYNCDRAW); 117 | 118 | C2D_TargetClear(top, C2D_Color32(0x42, 0x42, 0x42, 0xFF)); //上画面 119 | C2D_SceneBegin(top); 120 | 121 | get_option(&Option); 122 | 123 | switch (scene_state) { 124 | 125 | case SCENE_SELECTLOAD: //ロード画面 126 | 127 | snprintf(get_buffer(), BUFFER_SIZE, "TJAPlayer for 3DS %s", VERSION); 128 | load_sprites(); 129 | load_sound(); 130 | draw_select_text(120, 70, get_buffer()); 131 | draw_select_text(120, 100, "Now Loading..."); 132 | C3D_FrameEnd(0); 133 | load_file_main(); 134 | load_option(); 135 | if (check_dsp1() == true) scene_state = SCENE_SELECTSONG; 136 | else { 137 | warning = WARNING_DSP1; 138 | scene_state = SCENE_WARNING; 139 | } 140 | break; 141 | 142 | case SCENE_WARNING: //警告画面 143 | 144 | C2D_TargetClear(bottom, C2D_Color32(0x42, 0x42, 0x42, 0xFF)); //下画面 145 | C2D_SceneBegin(bottom); 146 | 147 | switch (warning) { 148 | case WARNING_DSP1: 149 | tmp = message_window(tp, key, TEXT_WARNING_DSP1); 150 | break; 151 | 152 | case WARNING_WAVE_NO_EXIST: 153 | tmp = message_window(tp, key, TEXT_WARNING_WAVE_NO_EXIST); 154 | break; 155 | 156 | case WARNING_WAVE_NOT_OGG: 157 | tmp = message_window(tp, key, TEXT_WARNING_WAVE_NOT_OGG); 158 | break; 159 | } 160 | if (tmp == 1 || key & KEY_A) { 161 | scene_state = SCENE_SELECTSONG; 162 | warning = -1; 163 | } 164 | break; 165 | 166 | case SCENE_SELECTSONG: //選曲 167 | 168 | if (key & KEY_START) isExit = true; 169 | 170 | if (cnt == 0) { 171 | select_ini(); 172 | } 173 | 174 | if (key & KEY_UP) update_cursor(KEY_UP); 175 | if (key & KEY_DOWN) update_cursor(KEY_DOWN); 176 | if (key & KEY_RIGHT) update_cursor(KEY_RIGHT); 177 | if (key & KEY_LEFT) update_cursor(KEY_LEFT); 178 | if (key & KEY_A) update_cursor(KEY_A); 179 | if (key & KEY_B) update_cursor(KEY_B); 180 | 181 | disp_file_list(); 182 | 183 | if (get_isGameStart() == true) { 184 | scene_state = SCENE_MAINLOAD; 185 | cnt = -1; 186 | } 187 | get_SelectedId(&SelectedSong, &course); 188 | 189 | C2D_TargetClear(bottom, C2D_Color32(0x42, 0x42, 0x42, 0xFF)); //下画面 190 | C2D_SceneBegin(bottom); 191 | draw_option(tp.px, tp.py, key, sprites); 192 | isPause = false; 193 | 194 | break; 195 | 196 | case SCENE_MAINLOAD: 197 | 198 | init_tja(); 199 | load_tja_head(course, SelectedSong); 200 | //init_main_music(); 201 | get_tja_header(&TJA_Header); 202 | init_score(); 203 | init_notes(TJA_Header); 204 | if (SelectedSong.course_exist[course] == false) load_tja_notes(-1, SelectedSong); 205 | else load_tja_notes(course, SelectedSong); 206 | time_ini(); 207 | offset = TJA_Header.offset + Option.offset; 208 | notes_cnt = 0; 209 | isNotesStart = false, isMusicStart = false, isPlayMain = false; 210 | FirstMeasureTime = INT_MAX; 211 | CurrentTimeMain = -1000; 212 | 213 | tmp = check_wave(SelectedSong); 214 | if (tmp == -1) scene_state = SCENE_MAINGAME; 215 | else { 216 | 217 | warning = tmp; 218 | scene_state = SCENE_WARNING; 219 | select_ini(); 220 | } 221 | cnt = -60; 222 | break; 223 | 224 | case SCENE_MAINGAME: //メイン 225 | 226 | C2D_DrawSprite(&sprites[SPRITE_TOP]); 227 | draw_title(); 228 | draw_emblem(sprites); 229 | 230 | if (cnt == 0) { 231 | 232 | FirstMeasureTime = get_FirstMeasureTime(); 233 | play_main_music(&isPlayMain, SelectedSong); 234 | } 235 | 236 | if (cnt >= 0) CurrentTimeMain = get_current_time(TIME_MAINGAME); 237 | 238 | if (Option.dispFps == true) draw_fps(); 239 | 240 | //譜面が先 241 | if (offset > 0 && (isNotesStart == false || isMusicStart == false)) { 242 | 243 | if (CurrentTimeMain >= 0 && isNotesStart == false) isNotesStart = true; 244 | if (CurrentTimeMain >= offset + FirstMeasureTime && isMusicStart == false) { 245 | isPlayMain = true; 246 | isMusicStart = true; 247 | } 248 | } 249 | 250 | //音楽が先 251 | else if (offset <= 0 && (isNotesStart == false || isMusicStart == false)) { 252 | 253 | if (CurrentTimeMain >= FirstMeasureTime && isPlayMain == false) { 254 | isPlayMain = true; 255 | isMusicStart = true; 256 | } 257 | if (CurrentTimeMain >= (-1.0) * offset && isNotesStart == false) { 258 | isNotesStart = true; 259 | } 260 | } 261 | 262 | if (isPause == false) { 263 | 264 | if (tp.px != 0 && tp.py != 0) { 265 | 266 | PreTouch_x = touch_x, PreTouch_y = touch_y; 267 | touch_x = tp.px, touch_y = tp.py; 268 | 269 | if ( 270 | (key & KEY_TOUCH || 271 | pow((touch_x - PreTouch_x)*(touch_x - PreTouch_x) + (touch_y - PreTouch_y)*(touch_y - PreTouch_y), 0.5) > 20.0 272 | ) && 273 | (tp.px - 160)*(tp.px - 160) + (tp.py - 135)*(tp.py - 135) <= 105 * 105 && 274 | touch_cnt < 2) { 275 | isDon = true; 276 | touch_cnt++; 277 | } 278 | else if ( 279 | ( 280 | key & KEY_TOUCH || 281 | pow((touch_x - PreTouch_x)*(touch_x - PreTouch_x) + (touch_y - PreTouch_y)*(touch_y - PreTouch_y), 0.5) > 20.0 282 | )&& 283 | touch_cnt < 2) { 284 | isKatsu = true; 285 | touch_cnt++; 286 | } 287 | } 288 | else { 289 | touch_x = 0, touch_y = 0, touch_cnt = 0, PreTouch_x = 0, PreTouch_y = 0; 290 | } 291 | 292 | button_game(&isDon, &isKatsu, Option, key); 293 | } 294 | 295 | if (isDon == true) play_sound(SOUND_DON); //ドン 296 | if (isKatsu == true) play_sound(SOUND_KATSU); //カツ 297 | 298 | if (key & KEY_SELECT || key & KEY_START) { 299 | togglePlayback(); 300 | toggle_time(0); 301 | toggle_time(1); 302 | isPause = !isPause; 303 | } 304 | 305 | draw_lane(sprites); 306 | draw_gauge(sprites); 307 | 308 | if (isNotesStart == true) { 309 | tja_to_notes(isDon, isKatsu, notes_cnt, sprites); 310 | if (isPause == false) notes_cnt++; 311 | } 312 | draw_score(sprites); 313 | 314 | C2D_TargetClear(bottom, C2D_Color32(0x42, 0x42, 0x42, 0xFF)); //下画面 315 | C2D_SceneBegin(bottom); 316 | C2D_DrawSprite(&sprites[SPRITE_BOTTOM]); 317 | //debug_touch(tp.px,tp.py); 318 | 319 | if (isPause == true) { 320 | 321 | tmp = pause_window(tp, key); 322 | 323 | switch (tmp) { 324 | case 0: 325 | break; 326 | 327 | case 1: 328 | isPlayMain = true; 329 | stopPlayback(); 330 | scene_state = SCENE_MAINLOAD; 331 | break; 332 | 333 | case 2: 334 | isPlayMain = true; 335 | stopPlayback(); 336 | cnt = -1; 337 | scene_state = SCENE_SELECTSONG; 338 | break; 339 | } 340 | 341 | if (tmp > -1) { 342 | togglePlayback(); 343 | toggle_time(0); 344 | toggle_time(1); 345 | isPause = !isPause; 346 | play_sound(SOUND_DON); 347 | } 348 | } 349 | if (get_notes_finish() == true && ndspChnIsPlaying(CHANNEL) == false) { 350 | scene_state = SCENE_RESULT; 351 | cnt = -1; 352 | } 353 | break; 354 | 355 | case SCENE_RESULT: 356 | 357 | if (key & KEY_START) { 358 | cnt = -1; 359 | scene_state = SCENE_SELECTSONG; 360 | } 361 | draw_gauge_result(sprites); 362 | draw_result(); 363 | break; 364 | } 365 | 366 | C2D_Flush(); 367 | C3D_FrameEnd(0); 368 | if (isPause == false) cnt++; 369 | } 370 | 371 | exit_main(); 372 | return 0; 373 | } 374 | 375 | void load_sprites() { 376 | 377 | spriteSheet = C2D_SpriteSheetLoad("romfs:/gfx/sprites.t3x"); 378 | if (!spriteSheet) svcBreak(USERBREAK_PANIC); 379 | 380 | for (int i = 0; i < SPRITES_NUMER; i++) { 381 | C2D_SpriteFromSheet(&sprites[i], spriteSheet, i); 382 | C2D_SpriteSetCenter(&sprites[i], 0.5f, 0.5f); 383 | } 384 | C2D_SpriteSetCenterRaw(&sprites[SPRITE_BALLOON], 13, 13); 385 | C2D_SpriteSetCenterRaw(&sprites[SPRITE_BALLOON_1], 9, 12); 386 | C2D_SpriteSetCenterRaw(&sprites[SPRITE_BALLOON_2], 9, 26); 387 | C2D_SpriteSetCenterRaw(&sprites[SPRITE_BALLOON_3], 9, 31); 388 | C2D_SpriteSetCenterRaw(&sprites[SPRITE_BALLOON_4], 9, 45); 389 | C2D_SpriteSetCenterRaw(&sprites[SPRITE_BALLOON_5], 9, 51); 390 | C2D_SpriteSetCenterRaw(&sprites[SPRITE_BALLOON_6], 9, 59); 391 | for (int i = 0; i < 4; i++) C2D_SpriteSetPos(&sprites[SPRITE_EFFECT_PERFECT + i], 93, 109); 392 | 393 | C2D_SpriteSetPos(&sprites[SPRITE_EFFECT_GOGO], 110, 92); 394 | 395 | C2D_SpriteSetPos(&sprites[SPRITE_TOP], TOP_WIDTH / 2, TOP_HEIGHT / 2); 396 | C2D_SpriteSetPos(&sprites[SPRITE_BOTTOM], BOTTOM_WIDTH / 2, BOTTOM_HEIGHT / 2); 397 | for (int i = 0; i < 5; i++)C2D_SpriteSetPos(&sprites[SPRITE_EMBLEM_EASY + i], 31, 113); 398 | } 399 | 400 | bool get_isPause() { 401 | 402 | return isPause; 403 | } 404 | 405 | void debug_touch(int x,int y) { 406 | 407 | snprintf(buffer, sizeof(buffer), "%d:%d:%.1f\n%d:%d:%d", 408 | PreTouch_x-touch_x, 409 | PreTouch_y-touch_y, 410 | pow((touch_x - PreTouch_x)*(touch_x - PreTouch_x) + (touch_y - PreTouch_y)*(touch_y - PreTouch_y), 0.5), 411 | touch_x,touch_y,touch_cnt); 412 | draw_debug(0, 0, buffer); 413 | } 414 | 415 | bool get_isMusicStart() { 416 | 417 | return isMusicStart; 418 | } 419 | 420 | char *get_buffer() { 421 | 422 | return buffer; 423 | } 424 | 425 | int powi(int x, int y) { //なぜかpowのキャストが上手くいかないので整数用powを自作 426 | 427 | int ans = 1; 428 | 429 | for (int i = 0; i < y; i++) { 430 | ans = ans * x; 431 | } 432 | return ans; 433 | } 434 | 435 | C2D_TextBuf g_MainText = C2D_TextBufNew(4096); 436 | C2D_Text MainText; 437 | 438 | void draw_window_text(float x, float y, const char* text, float* width, float* height,float size = 1.0) { 439 | 440 | C2D_TextBufClear(g_MainText); 441 | C2D_TextParse(&MainText, g_MainText, text); 442 | C2D_TextOptimize(&MainText); 443 | 444 | C2D_TextGetDimensions(&MainText, size, size, width, height); 445 | C2D_DrawText(&MainText, C2D_WithColor, BOTTOM_WIDTH / 2 - *width / 2, y, 1.0f, size, size, C2D_Color32f(1.0f, 1.0f, 1.0f, 1.0f)); 446 | } 447 | 448 | int pause_window(touchPosition tp, unsigned int key) { 449 | 450 | int margin = 20, result = -1, x, y; 451 | float width, height; 452 | 453 | C2D_DrawRectSolid(margin, margin, 0, BOTTOM_WIDTH - margin * 2, BOTTOM_HEIGHT - margin * 2, C2D_Color32f(0, 0, 0, 1)); 454 | 455 | draw_window_text(-1, margin + 30, Text[get_lang()][TEXT_CONTINUE], &width, &height); //続ける 456 | x = BOTTOM_WIDTH / 2 - width / 2, y = margin + 30; 457 | if ((y < tp.py && y + height > tp.py && x < tp.px && x + width > tp.px) && key & KEY_TOUCH) result = 0; 458 | 459 | draw_window_text(-1, margin + 80, Text[get_lang()][TEXT_STARTOVER], &width, &height); //はじめから 460 | x = BOTTOM_WIDTH / 2 - width / 2, y = margin + 80; 461 | if ((y < tp.py && y + height > tp.py && x < tp.px && x + width > tp.px) && key & KEY_TOUCH) result = 1; 462 | 463 | draw_window_text(-1, margin + 130, Text[get_lang()][TEXT_RETURNSELECT], &width, &height); //曲選択に戻る 464 | x = BOTTOM_WIDTH / 2 - width / 2, y = margin + 130; 465 | if ((y < tp.py && y + height > tp.py && x < tp.px && x + width > tp.px) && key & KEY_TOUCH) result = 2; 466 | 467 | return result; 468 | } 469 | 470 | int message_window(touchPosition tp, unsigned int key,int text) { 471 | 472 | int margin = 20,result = -1, x, y; 473 | float width, height; 474 | 475 | C2D_DrawRectSolid(margin, margin, 0, BOTTOM_WIDTH - margin * 2, BOTTOM_HEIGHT - margin * 2, C2D_Color32f(0, 0, 0, 1)); 476 | draw_window_text(-1, margin + 50, Text[get_lang()][text], &width, &height,0.5); 477 | 478 | draw_window_text(-1, margin + 150, "OK", &width, &height); 479 | x = BOTTOM_WIDTH / 2 - width / 2, y = margin + 150; 480 | if ((y < tp.py && y + height > tp.py && x < tp.px && x + width > tp.px) && key & KEY_TOUCH) result = 1; 481 | 482 | return result; 483 | } -------------------------------------------------------------------------------- /source/score.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "notes.h" 3 | #include "tja.h" 4 | #include "main.h" 5 | #include "score.h" 6 | #include "result.h" 7 | 8 | bool isGOGO; 9 | int combo, init, diff, DiffMul, scoremode, HitScore, ScoreDiff, BaseCeilingPoint, 10 | CurrentScore, TotalScore, CurrentTotalRollCount, CurrentRollCount, TotalRollCount, TotalPerfectCount, TotalNiceCount, TotalBadCount, 11 | CurrentPerfectCount, CurrentNiceCount, CurrentBadCount, CurrentBalloonCount, MaxComboCount; 12 | double tmp, Precision, CurrentPrecision; 13 | TJA_HEADER_T TJA_Header; 14 | char buf_score[160]; 15 | GAUGE_T Gauge; 16 | 17 | void init_guage_structure() { 18 | 19 | Gauge.perfect = 0; 20 | Gauge.nice = 0; 21 | Gauge.bad = 0; 22 | Gauge.score = 0; 23 | Gauge.norma = 0; 24 | Gauge.soul = 0; 25 | } 26 | 27 | void init_score() { 28 | 29 | isGOGO = false; 30 | combo = 0; 31 | get_tja_header(&TJA_Header); 32 | init = TJA_Header.scoreinit; 33 | diff = TJA_Header.scorediff; 34 | DiffMul = 0; 35 | scoremode = TJA_Header.scoremode; 36 | HitScore = 0; 37 | ScoreDiff = 0; 38 | BaseCeilingPoint = 0; 39 | CurrentScore = 0; 40 | TotalScore = 0; 41 | CurrentRollCount = 0; 42 | CurrentTotalRollCount = 0; 43 | TotalRollCount = 0; 44 | TotalPerfectCount = 0; 45 | TotalNiceCount = 0; 46 | TotalBadCount = 0; 47 | CurrentPerfectCount = 0; 48 | CurrentNiceCount = 0; 49 | CurrentBadCount = 0; 50 | Precision = 0; 51 | CurrentPrecision = 0; 52 | CurrentBalloonCount = 0; 53 | MaxComboCount = 0; 54 | init_guage_structure(); 55 | } 56 | 57 | 58 | void update_score(int knd) { 59 | 60 | int PreScore = TotalScore; 61 | bool isCombo = false; 62 | 63 | //if (scoremode == 1 || scoremode == 2) { 64 | 65 | double GOGOMul; 66 | if (isGOGO == true) GOGOMul = 1.2; 67 | else GOGOMul = 1.0; 68 | 69 | if (scoremode == 0) { //ドンダフル配点 70 | if (combo < 200) DiffMul = 0; 71 | else DiffMul = 1; 72 | } 73 | else if (scoremode == 2) { //新配点 74 | if (0 <= combo && combo < 9) DiffMul = 0; 75 | else if (9 <= combo && combo < 29) DiffMul = 1; 76 | else if (29 <= combo && combo < 49) DiffMul = 2; 77 | else if (49 <= combo && combo < 99) DiffMul = 4; 78 | else if (99 <= combo) DiffMul = 8; 79 | } 80 | else if (scoremode == 1) { //旧配点 81 | DiffMul = (combo + 1) / 10; 82 | if (combo > 100) DiffMul = 10; 83 | } 84 | 85 | HitScore = init + diff * DiffMul; 86 | 87 | switch (knd) { 88 | 89 | case PERFECT: 90 | TotalScore += round_down(HitScore * GOGOMul); 91 | CurrentScore += round_down(HitScore * GOGOMul); 92 | combo++; 93 | isCombo = true; 94 | TotalPerfectCount++; 95 | CurrentPerfectCount++; 96 | Gauge.score += Gauge.perfect; 97 | break; 98 | 99 | case SPECIAL_PERFECT: 100 | TotalScore += round_down(HitScore * GOGOMul) * 2; 101 | CurrentScore += round_down(HitScore * GOGOMul) * 2; 102 | combo++; 103 | isCombo = true; 104 | TotalPerfectCount++; 105 | CurrentPerfectCount++; 106 | Gauge.score += Gauge.perfect; 107 | break; 108 | 109 | case NICE: 110 | TotalScore += round_down(HitScore / 2); 111 | CurrentScore += round_down(HitScore / 2); 112 | combo++; 113 | isCombo = true; 114 | TotalNiceCount++; 115 | CurrentNiceCount++; 116 | Gauge.score += Gauge.nice; 117 | break; 118 | 119 | case SPECIAL_NICE: 120 | TotalScore += round_down(HitScore - 10); 121 | CurrentScore += round_down(HitScore - 10); 122 | combo++; 123 | isCombo = true; 124 | TotalNiceCount++; 125 | CurrentNiceCount++; 126 | Gauge.score += Gauge.nice; 127 | break; 128 | 129 | case BAD: 130 | combo = 0; 131 | TotalBadCount++; 132 | CurrentBadCount++; 133 | Gauge.score -= Gauge.bad; 134 | break; 135 | 136 | case THROUGH: 137 | combo = 0; 138 | TotalBadCount++; 139 | CurrentBadCount++; 140 | Gauge.score -= Gauge.bad; 141 | break; 142 | 143 | case BALLOON: 144 | case ROLL: 145 | if (scoremode == 0 || scoremode == 1) { //旧配点 146 | if (isGOGO == true) { 147 | TotalScore += 120; 148 | CurrentScore += 120; 149 | } 150 | else { 151 | TotalScore += 100; 152 | CurrentScore += 100; 153 | } 154 | } 155 | else if (scoremode == 2) { //新配点 156 | if (isGOGO == true) { 157 | TotalScore += 360; 158 | CurrentScore += 360; 159 | } 160 | else { 161 | TotalScore += 300; 162 | CurrentScore += 300; 163 | } 164 | } 165 | 166 | if (knd == ROLL) { 167 | CurrentRollCount++; 168 | CurrentTotalRollCount++; 169 | TotalRollCount++; 170 | } 171 | break; 172 | 173 | case BIG_ROLL: 174 | if (scoremode == 0 || scoremode == 1) { //旧配点 175 | if (isGOGO == true) { 176 | TotalScore += 430; 177 | CurrentScore += 430; 178 | } 179 | else { 180 | TotalScore += 360; 181 | CurrentScore += 360; 182 | } 183 | } 184 | else if (scoremode == 2) { //新配点 185 | if (isGOGO == true) { 186 | TotalScore += 240; 187 | CurrentScore += 240; 188 | } 189 | else { 190 | TotalScore += 200; 191 | CurrentScore += 200; 192 | } 193 | } 194 | CurrentTotalRollCount++; 195 | TotalRollCount++; 196 | CurrentRollCount++; 197 | break; 198 | 199 | case BALLOON_BREAK: 200 | if (isGOGO == true) { 201 | TotalScore += 6000; 202 | CurrentScore += 6000; 203 | } 204 | else { 205 | TotalScore += 5000; 206 | CurrentScore += 5000; 207 | } 208 | break; 209 | 210 | case ROLL_END: 211 | CurrentRollCount = 0; 212 | break; 213 | 214 | default: 215 | break; 216 | } 217 | //} 218 | 219 | if (combo > MaxComboCount) MaxComboCount = combo; 220 | if (Gauge.score < 0) Gauge.score = 0; 221 | 222 | if (scoremode == 2) { //100コンボ毎のボーナス(新配点のみ) 223 | if (isCombo == true && combo % 100 == 0) { 224 | TotalScore += 10000; 225 | CurrentScore += 10000; 226 | } 227 | } 228 | ScoreDiff = TotalScore - PreScore; 229 | if ((TotalPerfectCount + TotalNiceCount + TotalBadCount) != 0) Precision = (double)TotalPerfectCount / (TotalPerfectCount + TotalNiceCount + TotalBadCount) * 100.0; 230 | else Precision = 0; 231 | if ((CurrentPerfectCount + CurrentNiceCount + CurrentBadCount) != 0) CurrentPrecision = (double)CurrentPerfectCount / (CurrentPerfectCount + CurrentNiceCount + CurrentBadCount) * 100.0; 232 | else CurrentPrecision = 0; 233 | } 234 | 235 | void debug_score() { 236 | 237 | snprintf(buf_score, sizeof(buf_score), "Scoremode:%d Init:%d Diff:%d", TJA_Header.scoremode, init, diff); 238 | draw_debug(0, 10, buf_score); 239 | snprintf(buf_score, sizeof(buf_score), "%s %s", TJA_Header.title, TJA_Header.subtitle); 240 | draw_debug(0, 30, buf_score); 241 | snprintf(buf_score, sizeof(buf_score), "Course:%d Level:%d %s", TJA_Header.course, TJA_Header.level, TJA_Header.wave); 242 | draw_debug(0, 40, buf_score); 243 | snprintf(buf_score, sizeof(buf_score), "Score:%d %dCombo diff:%d", TotalScore, combo, ScoreDiff); 244 | draw_debug(0, 150, buf_score); 245 | snprintf(buf_score, sizeof(buf_score), "Current Score:%d Roll:%d Precision:%.1f", CurrentScore, CurrentTotalRollCount, CurrentPrecision); 246 | draw_debug(0, 160, buf_score); 247 | snprintf(buf_score, sizeof(buf_score), "良:%d 可:%d 不可:%d ゲージ%d", Gauge.perfect, Gauge.nice, Gauge.bad, Gauge.score); 248 | draw_debug(0, 170, buf_score); 249 | if (isGOGO == true) { 250 | snprintf(buf_score, sizeof(buf_score), "GOGOTIME"); 251 | draw_debug(0, 190, buf_score); 252 | } 253 | } 254 | 255 | void draw_score(C2D_Sprite sprites[SPRITES_NUMER]) { 256 | 257 | //スコア 258 | for (int i = 0; i < 7; i++) { 259 | 260 | if (TotalScore / powi(10, i) > 0) { 261 | int n = TotalScore / powi(10, i) % 10; 262 | C2D_SpriteSetPos(&sprites[SPRITE_SCORE_0 + n], 80 - i * 12, 70); 263 | C2D_DrawSprite(&sprites[SPRITE_SCORE_0 + n]); 264 | } 265 | } 266 | 267 | int j; 268 | 269 | //コンボ 270 | for (j = 0; j < 5; j++) { 271 | if (combo / powi(10, j) == 0) break; 272 | } 273 | for (int i = 0; i < 4; i++) { 274 | 275 | if (combo >= 10 && combo / powi(10, i) > 0) { 276 | 277 | int n = combo / powi(10, i) % 10; 278 | 279 | if (combo < 100) { 280 | C2D_SpriteSetPos(&sprites[SPRITE_COMBO_0 + n], 22 + j * 8 - i * 16, 110); 281 | C2D_DrawSprite(&sprites[SPRITE_COMBO_0 + n]); 282 | } 283 | else { 284 | C2D_SpriteSetPos(&sprites[SPRITE_COMBO_0_RED + n], 22 + j * 8 - i * 16, 110); 285 | C2D_DrawSprite(&sprites[SPRITE_COMBO_0_RED + n]); 286 | } 287 | } 288 | } 289 | 290 | //連打 291 | for (j = 0; j < 4; j++) { 292 | if (CurrentRollCount / powi(10, j) == 0) break; 293 | } 294 | if (CurrentRollCount > 0) { 295 | C2D_SpriteSetPos(&sprites[SPRITE_ROLL_COUNT], 110, 35); 296 | C2D_DrawSprite(&sprites[SPRITE_ROLL_COUNT]); 297 | } 298 | for (int i = 0; i < 4; i++) { 299 | 300 | if (CurrentRollCount / powi(10, i) > 0) { 301 | 302 | int n = CurrentRollCount / powi(10, i) % 10; 303 | C2D_SpriteSetPos(&sprites[SPRITE_ROLL_0 + n], 95 + j * 10 - i * 20, 30); 304 | C2D_DrawSprite(&sprites[SPRITE_ROLL_0 + n]); 305 | } 306 | } 307 | 308 | //風船 309 | for (j = 0; j < 4; j++) { 310 | if (CurrentBalloonCount / powi(10, j) == 0) break; 311 | } 312 | if (CurrentBalloonCount > 0) { 313 | C2D_SpriteSetPos(&sprites[SPRITE_BALLOON_COUNT], 110, 35); 314 | C2D_DrawSprite(&sprites[SPRITE_BALLOON_COUNT]); 315 | } 316 | for (int i = 0; i < 4; i++) { 317 | 318 | if (CurrentBalloonCount / powi(10, i) > 0) { 319 | 320 | int n = CurrentBalloonCount / powi(10, i) % 10; 321 | C2D_SpriteSetPos(&sprites[SPRITE_ROLL_0 + n], 97 + j * 10 - i * 20, 30); 322 | C2D_DrawSprite(&sprites[SPRITE_ROLL_0 + n]); 323 | } 324 | } 325 | } 326 | 327 | void draw_gauge(C2D_Sprite sprites[SPRITES_NUMER]) { 328 | 329 | double gauge = 1.0 * (Gauge.score / 200) * 200 / Gauge.soul; 330 | if (gauge > 1.0) gauge = 1.0; 331 | 332 | //赤 333 | C2D_DrawRectSolid(123, 76, 0, 250.0 * Gauge.norma / Gauge.soul, 8, C2D_Color32f(102.0 / 255, 0, 0, 1)); 334 | C2D_DrawRectSolid(123, 76, 0, 250.0 * gauge, 8, C2D_Color32f(1, 0, 0, 1)); 335 | 336 | //黄 337 | C2D_DrawRectSolid(123 + 250.0 * Gauge.norma / Gauge.soul, 67, 0, 250 - 250.0 * Gauge.norma / Gauge.soul, 17, C2D_Color32f(102.0 / 255, 68.0 / 255, 0, 1)); 338 | if (250 * gauge - (250.0 * Gauge.norma / Gauge.soul) >= 0) 339 | C2D_DrawRectSolid(123 + 250.0 * Gauge.norma / Gauge.soul, 67, 0, 250 * gauge - (250.0 * Gauge.norma / Gauge.soul), 17, C2D_Color32f(1, 1, 12.0 / 255, 1)); 340 | 341 | //魂 342 | for (int i = 0; i < 2; i++) C2D_SpriteSetPos(&sprites[SPRITE_SOUL_ON + i], 385, 75); 343 | C2D_SpriteSetPos(&sprites[SPRITE_SOUL_EFFECT], 395, 65); 344 | if ((Gauge.score / 200) * 200 >= Gauge.soul) { 345 | C2D_ImageTint Tint; 346 | C2D_AlphaImageTint(&Tint, 0.8); 347 | C2D_DrawSpriteTinted(&sprites[SPRITE_SOUL_EFFECT], &Tint); 348 | C2D_DrawSprite(&sprites[SPRITE_SOUL_ON]); 349 | } 350 | else C2D_DrawSprite(&sprites[SPRITE_SOUL_OFF]); 351 | } 352 | 353 | void draw_gauge_result(C2D_Sprite sprites[SPRITES_NUMER]) { 354 | 355 | int diff = 50; 356 | double x_start = 123 - diff, x_end = 250 - diff; 357 | double gauge = 1.0 * (Gauge.score / 200) * 200 / Gauge.soul; 358 | if (gauge > 1.0) gauge = 1.0; 359 | 360 | //赤 361 | C2D_DrawRectSolid(x_start, 76, 0, x_end * Gauge.norma / Gauge.soul, 8, C2D_Color32f(102.0 / 255, 0, 0, 1)); 362 | C2D_DrawRectSolid(x_start, 76, 0, x_end * gauge, 8, C2D_Color32f(1, 0, 0, 1)); 363 | 364 | //黄 365 | C2D_DrawRectSolid(x_start + x_end * Gauge.norma / Gauge.soul, 67, 0, x_end - x_end * Gauge.norma / Gauge.soul, 17, C2D_Color32f(102.0 / 255, 68.0 / 255, 0, 1)); 366 | if (x_end * gauge - (x_end * Gauge.norma / Gauge.soul) >= 0) 367 | C2D_DrawRectSolid(x_start + x_end * Gauge.norma / Gauge.soul, 67, 0, x_end * gauge - (x_end * Gauge.norma / Gauge.soul), 17, C2D_Color32f(1, 1, 12.0 / 255, 1)); 368 | 369 | //魂 370 | for (int i = 0; i < 2; i++) C2D_SpriteSetPos(&sprites[SPRITE_SOUL_ON + i], 385 - diff * 2, 75); 371 | C2D_SpriteSetPos(&sprites[SPRITE_SOUL_EFFECT], 395 - diff * 2, 65); 372 | if ((Gauge.score / 200) * 200 >= Gauge.soul) { 373 | C2D_ImageTint Tint; 374 | C2D_AlphaImageTint(&Tint, 0.8); 375 | C2D_DrawSpriteTinted(&sprites[SPRITE_SOUL_EFFECT], &Tint); 376 | C2D_DrawSprite(&sprites[SPRITE_SOUL_ON]); 377 | } 378 | else C2D_DrawSprite(&sprites[SPRITE_SOUL_OFF]); 379 | } 380 | 381 | void draw_lane(C2D_Sprite sprites[SPRITES_NUMER]) { 382 | 383 | 384 | if (get_isBranch() == true) { 385 | 386 | int branch = get_branch_course(); 387 | 388 | switch (branch) { 389 | case COMMAND_N: 390 | default: 391 | C2D_SpriteSetPos(&sprites[SPRITE_CHART_NORMAL], 350, 110); 392 | C2D_DrawSprite(&sprites[SPRITE_CHART_NORMAL]); 393 | break; 394 | 395 | case COMMAND_E: 396 | C2D_SpriteSetPos(&sprites[SPRITE_LANE_EXPERT], 233, 109); 397 | C2D_DrawSprite(&sprites[SPRITE_LANE_EXPERT]); 398 | C2D_SpriteSetPos(&sprites[SPRITE_CHART_EXPERT], 350, 110); 399 | C2D_DrawSprite(&sprites[SPRITE_CHART_EXPERT]); 400 | break; 401 | 402 | case COMMAND_M: 403 | C2D_SpriteSetPos(&sprites[SPRITE_LANE_MASTER], 233, 109); 404 | C2D_DrawSprite(&sprites[SPRITE_LANE_MASTER]); 405 | C2D_SpriteSetPos(&sprites[SPRITE_CHART_MASTER], 350, 110); 406 | C2D_DrawSprite(&sprites[SPRITE_CHART_MASTER]); 407 | break; 408 | } 409 | } 410 | 411 | C2D_SpriteSetPos(&sprites[SPRITE_JUDGE_CIRCLE], NOTES_JUDGE_X, 109); 412 | C2D_DrawSprite(&sprites[SPRITE_JUDGE_CIRCLE]); 413 | 414 | if (isGOGO == true) { 415 | C2D_ImageTint Tint; 416 | C2D_AlphaImageTint(&Tint, 0.8); 417 | C2D_DrawSpriteTinted(&sprites[SPRITE_EFFECT_GOGO], &Tint); 418 | } 419 | } 420 | 421 | int start_branch(int knd, double x, double y) { //分岐 422 | 423 | int branch; 424 | switch (knd) { 425 | case 0: //連打 426 | if (y <= CurrentTotalRollCount) branch = COMMAND_M; 427 | else if (x <= CurrentTotalRollCount) branch = COMMAND_E; 428 | else branch = COMMAND_N; 429 | break; 430 | case 1: //精度 431 | if (y <= CurrentPrecision) branch = COMMAND_M; 432 | else if (x <= CurrentPrecision) branch = COMMAND_E; 433 | else branch = COMMAND_N; 434 | break; 435 | case 2: //スコア 436 | if (y <= CurrentScore) branch = COMMAND_M; 437 | else if (x <= CurrentScore) branch = COMMAND_E; 438 | else branch = COMMAND_N; 439 | break; 440 | default: 441 | branch = COMMAND_N; 442 | break; 443 | } 444 | return branch; 445 | } 446 | 447 | void init_branch_section() { //#SECTION 448 | 449 | CurrentTotalRollCount = 0; 450 | CurrentPerfectCount = 0; 451 | CurrentNiceCount = 0; 452 | CurrentBadCount = 0; 453 | CurrentScore = 0; 454 | CurrentPrecision = 0; 455 | } 456 | 457 | void send_gogotime(bool arg) { 458 | isGOGO = arg; 459 | } 460 | 461 | int round_down(int arg) { 462 | int temp = arg % 10; 463 | return arg - temp; 464 | } 465 | 466 | void calc_base_score(MEASURE_T Measure[MEASURE_MAX], char notes[MEASURE_MAX][NOTES_MEASURE_MAX]) { //初項と公差を計算 魂ゲージの伸びも 467 | 468 | int NotesCount = 0, i = 0, combo = 0, DiffTmp = 0, BalloonCnt = 0, TmpBaseCeilingPoint = 0, NotesCountMax = 0, RollCnt = 0, RollKnd = 0; 469 | bool isEND = false; 470 | double init_cnt = 0, diff_cnt = 0, gogo = 1, special = 1, roll_start_time = 0, roll_end_time = 0; 471 | COMMAND_T Command; 472 | 473 | int PerfectNotesCount = 0; //魂ゲージの伸び計算用 474 | 475 | int level = TJA_Header.level; 476 | if (level > 10) level = 10; 477 | 478 | switch (TJA_Header.course) { //基本天井点を設定 479 | case 0: //かんたん 480 | BaseCeilingPoint = 280000 + level * 20000; 481 | break; 482 | case 1: //ふつう 483 | BaseCeilingPoint = 350000 + level * 50000; 484 | break; 485 | case 2: //むずかしい 486 | BaseCeilingPoint = 500000 + level * 50000; 487 | break; 488 | case 3: //おに 489 | case 4: 490 | if (level == 10) BaseCeilingPoint = 1200000; 491 | else BaseCeilingPoint = 650000 + level * 50000; 492 | break; 493 | } 494 | TmpBaseCeilingPoint = BaseCeilingPoint; 495 | 496 | 497 | while (isEND == false && i < MEASURE_MAX && Measure[i].flag == true) { //小節 498 | 499 | NotesCount = 0; 500 | 501 | if (Measure[i].branch != -1 && Measure[i].branch != COMMAND_M) { 502 | 503 | i++; 504 | continue; 505 | } 506 | 507 | if (NotesCount == 0 && notes[i][0] == '#') { 508 | 509 | get_command_value(notes[i], &Command); 510 | 511 | switch (Command.knd) { 512 | case COMMAND_GOGOSTART: 513 | gogo = 1.2; 514 | break; 515 | case COMMAND_GOGOEND: 516 | gogo = 1.0; 517 | break; 518 | case COMMAND_END: 519 | isEND = true; 520 | break; 521 | default: 522 | break; 523 | 524 | } 525 | NotesCount = 0; 526 | i++; 527 | continue; 528 | } 529 | 530 | while (notes[i][NotesCount] != ',' && notes[i][NotesCount] != '\n' && notes[i][NotesCount] != '/') { 531 | 532 | NotesCount++; 533 | } 534 | if (Measure[i].firstmeasure != -1) NotesCountMax = Measure[Measure[i].firstmeasure].max_notes; 535 | else NotesCountMax = NotesCount; 536 | 537 | for (int j = 0; j < NotesCount; j++) { //ノーツ 538 | 539 | int knd = ctoi(notes[i][j]); 540 | 541 | if (knd != 0) { 542 | 543 | if (knd == NOTES_DON || knd == NOTES_KATSU || knd == NOTES_BIGDON || knd == NOTES_BIGKATSU) { 544 | if (knd == NOTES_BIGDON || knd == NOTES_BIGKATSU) special = 2.0; 545 | else special = 1.0; 546 | combo++; 547 | init_cnt += 1 * gogo * special; 548 | 549 | if (scoremode == 1) { //旧配点 550 | 551 | if (combo > 100) DiffTmp = 10; 552 | else DiffTmp = combo / 10; 553 | } 554 | else if (scoremode == 2) { //新配点 555 | 556 | if (combo >= 1 && combo <= 9) DiffTmp = 0; 557 | else if (combo >= 10 && combo <= 29) DiffTmp = 1; 558 | else if (combo >= 30 && combo <= 49) DiffTmp = 2; 559 | else if (combo >= 50 && combo <= 99) DiffTmp = 4; 560 | else if (combo >= 100) DiffTmp = 8; 561 | } 562 | 563 | diff_cnt += DiffTmp * gogo * special; 564 | 565 | PerfectNotesCount++; 566 | } 567 | else if (knd == NOTES_BALLOON) { //風船 568 | 569 | TmpBaseCeilingPoint -= (TJA_Header.balloon[BalloonCnt] * 300 + 5000) * gogo; 570 | BalloonCnt++; 571 | } 572 | else if (knd == NOTES_ROLL) { //連打 573 | 574 | roll_start_time = Measure[i].judge_time + 60.0 / Measure[i].bpm * 4 * Measure[i].measure * i / NotesCountMax; 575 | RollKnd = NOTES_ROLL; 576 | } 577 | else if (knd == NOTES_BIGROLL) { //大連打 578 | 579 | roll_start_time = Measure[i].judge_time + 60.0 / Measure[i].bpm * 4 * Measure[i].measure * i / NotesCountMax; 580 | RollKnd = NOTES_BIGROLL; 581 | } 582 | else if (knd == NOTES_ROLLEND) { 583 | 584 | if (roll_start_time != 0) { 585 | 586 | roll_end_time = Measure[i].judge_time + 60.0 / Measure[i].bpm * 4 * Measure[i].measure * i / NotesCountMax; 587 | RollCnt = (int)((roll_end_time - roll_start_time) / (1.0 / 12.0)); 588 | 589 | if (RollKnd == NOTES_ROLL) { 590 | if (scoremode == 1) { 591 | if (gogo == true) TmpBaseCeilingPoint -= RollCnt * 360; 592 | else TmpBaseCeilingPoint -= RollCnt * 300; 593 | } 594 | if (scoremode == 2) { 595 | if (gogo == true) TmpBaseCeilingPoint -= RollCnt * 120; 596 | else TmpBaseCeilingPoint -= RollCnt * 100; 597 | } 598 | } 599 | else if (RollKnd == NOTES_BIGROLL) { 600 | if (scoremode == 1) { 601 | if (gogo == true) TmpBaseCeilingPoint -= RollCnt * 430 * gogo; 602 | else TmpBaseCeilingPoint -= RollCnt * 360 * gogo; 603 | } 604 | if (scoremode == 1) { 605 | if (gogo == true) TmpBaseCeilingPoint -= RollCnt * 240 * gogo; 606 | else TmpBaseCeilingPoint -= RollCnt * 200 * gogo; 607 | } 608 | } 609 | roll_start_time = 0; 610 | roll_end_time = 0; 611 | RollCnt = 0; 612 | } 613 | } 614 | } 615 | } 616 | i++; 617 | } 618 | 619 | 620 | if ((TJA_Header.scoreinit == -1 || TJA_Header.scorediff == -1) && (scoremode == 1 || scoremode == 2)) { //新配点と旧配点 621 | diff = (TmpBaseCeilingPoint - (int)(combo / 100) * 10000) / (init_cnt * 4 + diff_cnt); 622 | init = diff * 4; 623 | } 624 | else if (scoremode == 0) { 625 | init = 1000; 626 | diff = 1000; 627 | } 628 | 629 | Gauge.perfect = 10000 / PerfectNotesCount; 630 | 631 | switch (TJA_Header.course) { //ゲージの伸び率の計算 632 | case 0: //かんたん 633 | Gauge.nice = Gauge.perfect * 3 / 4; 634 | Gauge.bad = Gauge.perfect / 2; 635 | if (level <= 1) { 636 | Gauge.norma = 3600; 637 | Gauge.soul = 6000; 638 | } 639 | else if (level <= 3) { 640 | Gauge.norma = 3800; 641 | Gauge.soul = 6333; 642 | } 643 | else if (level >= 4) { 644 | Gauge.norma = 4400; 645 | Gauge.soul = 7333; 646 | } 647 | break; 648 | 649 | case 1: //ふつう 650 | Gauge.nice = Gauge.perfect * 3 / 4; 651 | if (level <= 2) { 652 | Gauge.bad = Gauge.perfect / 2; 653 | Gauge.norma = 4595; 654 | Gauge.soul = 6560; 655 | } 656 | else if (level == 3) { 657 | Gauge.bad = Gauge.perfect / 2; 658 | Gauge.norma = 4868; 659 | Gauge.soul = 6955; 660 | } 661 | else if (level == 4) { 662 | Gauge.bad = Gauge.perfect * 3 / 4; 663 | Gauge.norma = 4925; 664 | Gauge.soul = 7035; 665 | } 666 | else if (level >= 5) { 667 | Gauge.bad = Gauge.perfect; 668 | Gauge.norma = 5250; 669 | Gauge.soul = 7500; 670 | } 671 | break; 672 | 673 | case 2: //むずかしい 674 | Gauge.nice = Gauge.perfect * 3 / 4; 675 | if (level <= 2) { 676 | Gauge.bad = Gauge.perfect / 2; 677 | Gauge.norma = 5450; 678 | Gauge.soul = 7750; 679 | } 680 | else if (level == 3) { 681 | Gauge.bad = Gauge.perfect; 682 | Gauge.norma = 5080; 683 | Gauge.soul = 7250; 684 | } 685 | else if (level <= 4) { 686 | Gauge.bad = Gauge.perfect * 7 / 6; 687 | Gauge.norma = 4840; 688 | Gauge.soul = 6910; 689 | } 690 | else if (level <= 5) { 691 | Gauge.bad = Gauge.perfect * 5 / 4; 692 | Gauge.norma = 4724; 693 | Gauge.soul = 6750; 694 | } 695 | else if (level >= 6) { 696 | Gauge.bad = Gauge.perfect * 5 / 4; 697 | Gauge.norma = 4812; 698 | Gauge.soul = 6875; 699 | } 700 | break; 701 | 702 | case 3: //おに 703 | default: 704 | Gauge.nice = Gauge.perfect / 2; 705 | if (level <= 7) { 706 | Gauge.bad = Gauge.perfect * 8 / 5; 707 | Gauge.norma = 5660; 708 | Gauge.soul = 7075; 709 | } 710 | else if (level == 8) { 711 | Gauge.bad = Gauge.perfect * 2; 712 | Gauge.norma = 5600; 713 | Gauge.soul = 7000; 714 | } 715 | else if (level >= 9) { 716 | Gauge.bad = Gauge.perfect * 2; 717 | Gauge.norma = 6000; 718 | Gauge.soul = 7500; 719 | } 720 | break; 721 | } 722 | //init_score_after(); 723 | } 724 | 725 | void update_balloon_count(int arg) { 726 | CurrentBalloonCount = arg; 727 | } 728 | 729 | void draw_emblem(C2D_Sprite sprites[SPRITES_NUMER]) { 730 | 731 | switch (TJA_Header.course) { 732 | case COURSE_EASY: 733 | C2D_DrawRectSolid(0, 86, 0, 62, 58, C2D_Color32f(1, 51.0 / 255.0, 0, 1)); 734 | C2D_DrawSprite(&sprites[SPRITE_EMBLEM_EASY]); 735 | break; 736 | case COURSE_NORMAL: 737 | C2D_DrawRectSolid(0, 86, 0, 62, 58, C2D_Color32f(136.0 / 255.0, 204.0 / 255.0, 34.0 / 255.0, 1)); 738 | C2D_DrawSprite(&sprites[SPRITE_EMBLEM_NORMAL]); 739 | break; 740 | case COURSE_HARD: 741 | C2D_DrawRectSolid(0, 86, 0, 62, 58, C2D_Color32f(51.0 / 255.0, 170.0 / 255.0, 187.0 / 255.0, 1)); 742 | C2D_DrawSprite(&sprites[SPRITE_EMBLEM_HARD]); 743 | break; 744 | case COURSE_ONI: 745 | C2D_DrawRectSolid(0, 86, 0, 62, 58, C2D_Color32f(1, 34.0 / 255.0, 204.0 / 255.0, 1)); 746 | C2D_DrawSprite(&sprites[SPRITE_EMBLEM_ONI]); 747 | break; 748 | case COURSE_EDIT: 749 | C2D_DrawRectSolid(0, 86, 0, 62, 58, C2D_Color32f(136.0 / 255.0, 34.0 / 255.0, 1, 1)); 750 | C2D_DrawSprite(&sprites[SPRITE_EMBLEM_EDIT]); 751 | break; 752 | } 753 | } 754 | 755 | void get_result(RESULT_T* Result) { 756 | 757 | Result->perfect = TotalPerfectCount; 758 | Result->nice = TotalNiceCount; 759 | Result->bad = TotalBadCount; 760 | Result->roll = TotalRollCount; 761 | Result->combo = MaxComboCount; 762 | Result->score = CurrentScore; 763 | } -------------------------------------------------------------------------------- /source/tja.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "notes.h" 3 | #include "tja.h" 4 | #include "score.h" 5 | #include "main.h" 6 | #include "select.h" 7 | #include "option.h" 8 | 9 | 10 | char tja_notes[MEASURE_MAX][NOTES_MEASURE_MAX]; 11 | int tja_cnt = 0, MeasureMaxNumber = 0; 12 | double MainFirstMeasureTime; //最初に"到達"する小節の到達所要時間 最初に"生成"はMeasure[0]で取得 13 | bool isBranch = false; 14 | 15 | 16 | TJA_HEADER_T Current_Header; 17 | MEASURE_T Measure[MEASURE_MAX]; 18 | 19 | void get_command_value(char* buf, COMMAND_T *Command); 20 | 21 | void init_measure_structure() { 22 | 23 | for (int i = 0; i < MEASURE_MAX; i++) { 24 | 25 | Measure[i].create_time = INT_MAX; 26 | Measure[i].judge_time = INT_MAX; 27 | Measure[i].pop_time = INT_MAX; 28 | Measure[i].bpm = 0; 29 | Measure[i].scroll = 0; 30 | Measure[i].notes = 0; 31 | Measure[i].flag = false; 32 | Measure[i].isDispBarLine = true; 33 | Measure[i].firstmeasure = -1; 34 | Measure[i].start_measure_count = 0; 35 | Measure[i].max_notes = 0; 36 | Measure[i].original_id = -1; 37 | Measure[i].notes_count = 0; 38 | Measure[i].command = -1; 39 | } 40 | } 41 | 42 | void init_tja() { 43 | 44 | init_measure_structure(); 45 | tja_cnt = 0; 46 | MeasureMaxNumber = 0; 47 | MainFirstMeasureTime = 0; 48 | isBranch = false; 49 | } 50 | 51 | void load_tja_head(int course,LIST_T Song) { 52 | 53 | FILE *fp; 54 | char buf[128]; 55 | bool isCourseMatch = true; 56 | 57 | Current_Header.title = (char*)"No title"; 58 | Current_Header.subtitle = (char*)""; 59 | Current_Header.subtitle_state = -1; 60 | Current_Header.level = 0; 61 | Current_Header.bpm = 60.0; 62 | Current_Header.wave = (char*)"audio.ogg"; 63 | Current_Header.offset = 0; 64 | Current_Header.balloon[0] = 5; 65 | Current_Header.songvol = 100; 66 | Current_Header.sevol = 100; 67 | Current_Header.scoreinit = -1; 68 | Current_Header.scorediff = -1; 69 | Current_Header.course = course; 70 | Current_Header.style = 1; 71 | Current_Header.life = -1; 72 | Current_Header.demostart = 0; 73 | Current_Header.side = 3; 74 | Current_Header.scoremode = 1; 75 | 76 | chdir(Song.path); 77 | int cnt = -1; 78 | 79 | if ((fp = fopen(Song.tja, "r")) != NULL) { 80 | 81 | char* temp = NULL; 82 | while (fgets(buf, 128, fp) != NULL) { 83 | 84 | cnt++; 85 | temp = (char *)malloc((strlen(buf) + 1)); 86 | 87 | 88 | if (isCourseMatch == true && strstr(buf, "#START") == buf) { 89 | break; 90 | } 91 | 92 | if (strstr(buf, "TITLE:") == buf) { 93 | if (buf[6] != '\n' && buf[6] != '\r') { 94 | strlcpy(temp, buf + 6, strlen(buf) - 7); 95 | Current_Header.title = temp; 96 | } 97 | continue; 98 | } 99 | if (cnt == 0) { 100 | if (strstr(buf, "TITLE:") == buf + 3 && strstr(buf, "SUBTITLE:") == 0) { 101 | if (buf[9] != '\n' && buf[9] != '\r') { 102 | strlcpy(temp, buf + 9, strlen(buf) - 10); 103 | Current_Header.title = temp; 104 | } 105 | continue; 106 | } 107 | } 108 | 109 | if (strstr(buf, "SUBTITLE:") == buf) { 110 | if (buf[9] != '\n' && buf[9] != '\r') { 111 | 112 | strlcpy(temp, buf + 9, strlen(buf) - 10); 113 | 114 | if (strstr(temp, "--") == temp) Current_Header.subtitle_state = 1; 115 | else if (strstr(temp, "++") == temp) Current_Header.subtitle_state = 2; 116 | else Current_Header.subtitle_state = 0; 117 | 118 | if (Current_Header.subtitle_state != 0) { 119 | strlcpy(temp, buf + 9 + 2, strlen(buf) - 10 - 2); 120 | } 121 | Current_Header.subtitle = temp; 122 | } 123 | continue; 124 | } 125 | 126 | if (strstr(buf, "LEVEL:") == buf) { 127 | if (buf[6] != '\n' && buf[6] != '\r') { 128 | strlcpy(temp, buf + 6, strlen(buf) - 7); 129 | Current_Header.level = atoi(temp); 130 | } 131 | continue; 132 | } 133 | 134 | if (strstr(buf, "BPM:") == buf) { 135 | if (buf[4] != '\n' && buf[4] != '\r') { 136 | strlcpy(temp, buf + 4, strlen(buf) - 5); 137 | Current_Header.bpm = atof(temp); 138 | } 139 | continue; 140 | } 141 | 142 | if (strstr(buf, "WAVE:") == buf) { 143 | if (buf[5] != '\n' && buf[5] != '\r') { 144 | strlcpy(temp, buf + 5, strlen(buf) - 6); 145 | Current_Header.wave = temp; 146 | } 147 | continue; 148 | } 149 | 150 | if (strstr(buf, "OFFSET:") == buf) { 151 | if (buf[7] != '\n' && buf[7] != '\r') { 152 | strlcpy(temp, buf + 7, strlen(buf) - 8); 153 | Current_Header.offset = atof(temp); 154 | } 155 | continue; 156 | } 157 | 158 | if (strstr(buf, "BALLOON:") == buf) { 159 | if (buf[8] != '\n' && buf[8] != '\r') { 160 | strlcpy(temp, buf + 8, strlen(buf) - 9); 161 | char *tp = strtok(temp, ","); 162 | Current_Header.balloon[0] = atoi(tp); 163 | int cnt = 1; 164 | while ((tp = strtok(NULL, ","))) { 165 | Current_Header.balloon[cnt] = atoi(tp); 166 | cnt++; 167 | } 168 | } 169 | continue; 170 | } 171 | 172 | if (strstr(buf, "SONGVOL:") == buf) { 173 | if (buf[8] != '\n' && buf[8] != '\r') { 174 | strlcpy(temp, buf + 8, strlen(buf) - 9); 175 | Current_Header.songvol = atoi(temp); 176 | } 177 | continue; 178 | } 179 | 180 | if (strstr(buf, "SEVOL:") == buf) { 181 | if (buf[6] != '\n' && buf[6] != '\r') { 182 | strlcpy(temp, buf + 6, strlen(buf) - 7); 183 | Current_Header.sevol = atoi(temp); 184 | } 185 | continue; 186 | } 187 | 188 | if (strstr(buf, "SCOREINIT:") == buf) { 189 | if (buf[10] != '\n' && buf[10] != '\r') { 190 | strlcpy(temp, buf + 10, strlen(buf) - 11); 191 | Current_Header.scoreinit = atoi(temp); 192 | } 193 | continue; 194 | } 195 | 196 | if (strstr(buf, "SCOREDIFF:") == buf) { 197 | if (buf[10] != '\n' && buf[10] != '\r') { 198 | strlcpy(temp, buf + 10, strlen(buf) - 11); 199 | Current_Header.scorediff = atoi(temp); 200 | } 201 | continue; 202 | } 203 | 204 | 205 | if (strstr(buf, "COURSE:") == buf) { 206 | if (buf[7] != '\n' && buf[7] != '\r') { 207 | strlcpy(temp, buf + 7, strlen(buf) - 8); 208 | if (strlen(temp) == 1) Current_Header.course = atoi(temp); //数字表記 209 | else if (strcmp(temp, "Easy") == 0 || strcmp(temp, "easy") == 0) course = COURSE_EASY; //文字表記 210 | else if (strcmp(temp, "Normal") == 0 || strcmp(temp, "normal") == 0) course = COURSE_NORMAL; 211 | else if (strcmp(temp, "Hard") == 0 || strcmp(temp, "hard") == 0) course = COURSE_HARD; 212 | else if (strcmp(temp, "Oni") == 0 || strcmp(temp, "oni") == 0) course = COURSE_ONI; 213 | else if (strcmp(temp, "Edit") == 0 || strcmp(temp, "edit") == 0) course = COURSE_EDIT; 214 | 215 | if (Current_Header.course == course) { 216 | isCourseMatch = true; 217 | } 218 | else isCourseMatch = false; 219 | } 220 | continue; 221 | } 222 | 223 | if (strstr(buf, "STYLE:") == buf) { 224 | if (buf[6] != '\n' && buf[6] != '\r') { 225 | strlcpy(temp, buf + 6, strlen(buf) - 7); 226 | Current_Header.style = atoi(temp); 227 | } 228 | continue; 229 | } 230 | 231 | if (strstr(buf, "LIFE:") == buf) { 232 | if (buf[5] != '\n' && buf[5] != '\r') { 233 | strlcpy(temp, buf + 5, strlen(buf) - 6); 234 | Current_Header.life = atoi(temp); 235 | } 236 | continue; 237 | } 238 | 239 | if (strstr(buf, "DEMOSTART:") == buf) { 240 | if (buf[10] != '\n' && buf[10] != '\r') { 241 | strlcpy(temp, buf + 10, strlen(buf) - 11); 242 | Current_Header.demostart = atof(temp); 243 | } 244 | continue; 245 | } 246 | 247 | if (strstr(buf, "SIDE:") == buf) { 248 | if (buf[5] != '\n' && buf[5] != '\r') { 249 | strlcpy(temp, buf + 5, strlen(buf) - 6); 250 | Current_Header.side = atoi(temp); 251 | } 252 | continue; 253 | } 254 | 255 | if (strstr(buf, "SCOREMODE:") == buf) { 256 | if (buf[10] != '\n' && buf[10] != '\r') { 257 | strlcpy(temp, buf + 10, strlen(buf) - 11); 258 | Current_Header.scoremode = atoi(temp); 259 | } 260 | continue; 261 | } 262 | 263 | free(temp); 264 | } 265 | 266 | fclose(fp); 267 | free(temp); 268 | 269 | } 270 | else { 271 | //tjaファイルが開けなかった時 272 | } 273 | } 274 | 275 | void load_tja_head_simple(LIST_T *List) { //選曲用のヘッダ取得 276 | 277 | 278 | snprintf(List->title, sizeof(List->title), "No Title"); 279 | snprintf(List->wave, sizeof(List->wave), "audio.ogg"); 280 | 281 | for (int i = 0; i < 5; i++) { 282 | List->level[i] = 0; 283 | List->course[i] = false; 284 | } 285 | 286 | FILE *fp; 287 | char buf[128],*temp = NULL;; 288 | int course = COURSE_ONI,cnt = 0; 289 | 290 | chdir(List->path); 291 | 292 | if ((fp = fopen(List->tja, "r")) != NULL) { 293 | 294 | while (fgets(buf, 128, fp) != NULL) { 295 | 296 | temp = (char *)malloc((strlen(buf) + 1)); 297 | 298 | if (strstr(buf, "TITLE:") == buf) { 299 | if (buf[6] != '\n' && buf[6] != '\r') { 300 | strlcpy(List->title, buf + 6, strlen(buf) - 7); 301 | } 302 | continue; 303 | } 304 | if (cnt == 0) { 305 | if (strstr(buf, "TITLE:") == buf+3 && strstr(buf, "SUBTITLE:") == 0) { 306 | if (buf[9] != '\n' && buf[9] != '\r') { 307 | strlcpy(List->title, buf + 9, strlen(buf) - 10); 308 | } 309 | continue; 310 | } 311 | } 312 | 313 | if (strstr(buf, "WAVE:") == buf) { 314 | if (buf[5] != '\n' && buf[5] != '\r') { 315 | strlcpy(List->wave, buf + 5, strlen(buf) - 6); 316 | } 317 | continue; 318 | } 319 | 320 | if (strstr(buf, "COURSE:") == buf) { 321 | if (buf[7] != '\n' && buf[7] != '\r') { 322 | strlcpy(temp, buf + 7, strlen(buf) - 8); 323 | if (strlen(temp) == 1) course = atoi(temp); //数字表記 324 | else if (strcmp(temp, "Easy") == 0 || strcmp(temp, "easy") == 0) course = COURSE_EASY; //文字表記 325 | else if (strcmp(temp, "Normal") == 0 || strcmp(temp, "normal") == 0) course = COURSE_NORMAL; 326 | else if (strcmp(temp, "Hard") == 0 || strcmp(temp, "hard") == 0) course = COURSE_HARD; 327 | else if (strcmp(temp, "Oni") == 0 || strcmp(temp, "oni") == 0) course = COURSE_ONI; 328 | else if (strcmp(temp, "Edit") == 0 || strcmp(temp, "edit") == 0) course = COURSE_EDIT; 329 | 330 | 331 | List->course[course] = true; 332 | List->course_exist[course] = true; 333 | } 334 | 335 | continue; 336 | } 337 | 338 | if (strstr(buf, "LEVEL:") == buf) { 339 | if (buf[6] != '\n' && buf[6] != '\r') { 340 | strlcpy(temp, buf + 6, strlen(buf) - 7); 341 | List->level[course] = atoi(temp); 342 | 343 | List->course[course] = true; 344 | } 345 | continue; 346 | } 347 | cnt++; 348 | } 349 | } 350 | 351 | 352 | free(temp); 353 | fclose(fp); 354 | } 355 | 356 | void sort_measure_insertion(MEASURE_T t[], int array_size) { //create_timeでソート 357 | 358 | for (int i = 1; i < array_size; i++) { 359 | 360 | MEASURE_T temp = t[i]; 361 | if (t[i - 1].create_time > temp.create_time) { 362 | 363 | int j = i; 364 | do { 365 | t[j] = t[j - 1]; 366 | --j; 367 | } while (j > 0 && t[j - 1].create_time > temp.create_time); 368 | t[j] = temp; 369 | } 370 | } 371 | } 372 | 373 | double calc_first_measure_time() { //最初に到達する小節の所要時間を計算 374 | 375 | int tmp = -1; 376 | 377 | for (int i = 0; i < MEASURE_MAX; i++) { 378 | 379 | if (Measure[i].flag == true && Measure[i].command == -1) { 380 | 381 | if (tmp == -1) { //初回 382 | tmp = i; 383 | continue; 384 | } 385 | 386 | if (Measure[i].judge_time < Measure[tmp].judge_time) tmp = i; 387 | } 388 | } 389 | 390 | return Measure[tmp].judge_time + Measure[0].create_time * -1; 391 | 392 | } 393 | 394 | void load_tja_notes(int course, LIST_T Song) { 395 | 396 | int FirstMultiMeasure = -1, //複数行の小節の最初の小節id 複数出ない場合は-1 397 | NotesCount = 0, BranchCourse = -1, 398 | BeforeBranchFirstMultiMeasure = -1, BeforeBranchNotesCount = 0; 399 | bool isStart = false, isEnd = false, isDispBarLine = true, isNoComma = false, isCourseMatch = false, 400 | BeforeBranchIsDispBarLine = true, BeforeBranchIsNoComma = false; 401 | FILE *fp; 402 | COMMAND_T Command; 403 | OPTION_T Option; 404 | get_option(&Option); 405 | 406 | double bpm = Current_Header.bpm, 407 | NextBpm = bpm, 408 | measure = 1, 409 | scroll = 1, 410 | NextMeasure = 1, 411 | delay = 0, 412 | percent = 1, 413 | BeforeBranchJudgeTime = 0,BeforeBranchCreateTime = 0,BeforeBranchPopTime = 0,BeforeBranchPreJudge = 0,BeforeBranchBpm = 0, 414 | BeforeBranchDelay = 0,BeforeBranchMeasure = 0,BeforeBranchScroll = 1,BeforeBranchNextBpm = 0,BeforeBranchNextMeasure = 0,BeforeBranchPercent = 1; 415 | 416 | if (course == -1) isCourseMatch = true; //コース表記なし 417 | 418 | chdir(Song.path); 419 | if ((fp = fopen(Song.tja, "r")) != NULL) { 420 | 421 | tja_cnt = 0; 422 | int MeasureCount = 0,CurrentCourse = -1; 423 | double PreJudge = 0, FirstMeasureTime = 0; 424 | 425 | FirstMeasureTime = (60.0 / bpm * 4 * measure)*(NOTES_JUDGE_RANGE / NOTES_AREA) - 60.0 / bpm * 4 * measure; 426 | PreJudge = FirstMeasureTime; 427 | 428 | 429 | while ( 430 | (fgets(tja_notes[tja_cnt], NOTES_MEASURE_MAX, fp) != NULL || tja_cnt < MEASURE_MAX) && 431 | isEnd == false 432 | ) { 433 | 434 | if (strstr(tja_notes[tja_cnt], "COURSE:") == tja_notes[tja_cnt]) { 435 | 436 | char* temp = NULL; 437 | temp = (char *)malloc((strlen(tja_notes[tja_cnt]) + 1)); 438 | 439 | strlcpy(temp, tja_notes[tja_cnt] + 7, strlen(tja_notes[tja_cnt]) - 8); 440 | if (strlen(temp) == 1) CurrentCourse = atoi(temp); //数字表記 441 | else if (strcmp(temp, "Easy") == 0 || strcmp(temp, "easy") == 0) CurrentCourse = COURSE_EASY; //文字表記 442 | else if (strcmp(temp, "Normal") == 0 || strcmp(temp, "normal") == 0) CurrentCourse = COURSE_NORMAL; 443 | else if (strcmp(temp, "Hard") == 0 || strcmp(temp, "hard") == 0) CurrentCourse = COURSE_HARD; 444 | else if (strcmp(temp, "Oni") == 0 || strcmp(temp, "oni") == 0) CurrentCourse = COURSE_ONI; 445 | else if (strcmp(temp, "Edit") == 0 || strcmp(temp, "edit") == 0) CurrentCourse = COURSE_EDIT; 446 | 447 | free(temp); 448 | 449 | if (course == CurrentCourse) isCourseMatch = true; 450 | 451 | continue; 452 | } 453 | 454 | if (isStart == false && isCourseMatch == true && strstr(tja_notes[tja_cnt], "#START") == tja_notes[tja_cnt]) { 455 | 456 | isStart = true; 457 | continue; 458 | } 459 | 460 | if (isStart == true && isCourseMatch == true) { 461 | 462 | //一文字目がコメントアウトの時スキップ 463 | if (strstr(tja_notes[tja_cnt], "//") == tja_notes[tja_cnt] || strstr(tja_notes[tja_cnt], "\r") == tja_notes[tja_cnt]) { 464 | 465 | tja_cnt++; 466 | continue; 467 | } 468 | 469 | if (strstr(tja_notes[tja_cnt], ",") == NULL && tja_notes[tja_cnt][0] != '#') { 470 | isNoComma = true; 471 | 472 | if (FirstMultiMeasure == -1) { 473 | 474 | FirstMultiMeasure = MeasureCount; 475 | Measure[FirstMultiMeasure].original_id = FirstMultiMeasure; //ソート前のidを格納 476 | } 477 | } 478 | else { 479 | isNoComma = false; 480 | } 481 | 482 | if (tja_notes[tja_cnt][0] == '#') { 483 | 484 | get_command_value(tja_notes[tja_cnt], &Command); 485 | Measure[MeasureCount].command = Command.knd; 486 | switch (Command.knd) { 487 | case COMMAND_BPMCHANGE: 488 | NextBpm = Command.val[0]; 489 | break; 490 | case COMMAND_MEASURE: 491 | NextMeasure = Command.val[0]; 492 | break; 493 | case COMMAND_SCROLL: 494 | scroll = Command.val[0]; 495 | break; 496 | case COMMAND_DELAY: 497 | delay = Command.val[0]; 498 | break; 499 | case COMMAND_BARLINEON: 500 | isDispBarLine = true; 501 | break; 502 | case COMMAND_BARLINEOFF: 503 | isDispBarLine = false; 504 | break; 505 | case COMMAND_N: 506 | BranchCourse = COMMAND_N; 507 | break; 508 | case COMMAND_E: 509 | BranchCourse = COMMAND_E; 510 | break; 511 | case COMMAND_M: 512 | BranchCourse = COMMAND_M; 513 | break; 514 | case COMMAND_BRANCHSTART: 515 | isBranch = true; 516 | break; 517 | case COMMAND_BRANCHEND: 518 | BranchCourse = -1; 519 | break; 520 | case COMMAND_SECTION: 521 | Measure[MeasureCount].command = COMMAND_SECTION; 522 | break; 523 | case COMMAND_END: 524 | isEnd = true; 525 | break; 526 | default: 527 | break; 528 | } 529 | } 530 | else { 531 | 532 | if (isNoComma == true || NotesCount != 0) { //複数小節 533 | 534 | Measure[MeasureCount].start_measure_count = NotesCount; 535 | int i = 0; 536 | while (tja_notes[tja_cnt][i] != '\n' && tja_notes[tja_cnt][i] != ',' && tja_notes[tja_cnt][i] != '/') i++; 537 | NotesCount += i - 1; 538 | if (tja_notes[tja_cnt][i] == '/') NotesCount++; 539 | if (tja_notes[tja_cnt][i] != ',' && tja_notes[tja_cnt][i] != '/') i--; 540 | Measure[MeasureCount].notes_count = i; 541 | 542 | } 543 | } 544 | 545 | Measure[MeasureCount].flag = true; 546 | Measure[MeasureCount].notes = tja_cnt; 547 | Measure[MeasureCount].firstmeasure = FirstMultiMeasure; 548 | Measure[MeasureCount].bpm = NextBpm; 549 | Measure[MeasureCount].measure = NextMeasure; 550 | Measure[MeasureCount].scroll = scroll; 551 | Measure[MeasureCount].judge_time = 60.0 / bpm * 4 * measure * percent + PreJudge + delay; 552 | Measure[MeasureCount].pop_time = Measure[MeasureCount].judge_time - (60.0 / Measure[MeasureCount].bpm * 4)*(NOTES_JUDGE_RANGE / NOTES_AREA); 553 | Measure[MeasureCount].create_time = Measure[MeasureCount].judge_time - (60.0 / Measure[MeasureCount].bpm * 4)*(NOTES_JUDGE_RANGE / (NOTES_AREA*scroll* Option.speed)); 554 | Measure[MeasureCount].isDispBarLine = isDispBarLine; 555 | Measure[MeasureCount].branch = BranchCourse; 556 | 557 | if (tja_notes[tja_cnt][0] == '#') { 558 | 559 | if (MeasureCount > 0) { 560 | Measure[MeasureCount].judge_time = Measure[MeasureCount - 1].judge_time; 561 | Measure[MeasureCount].create_time = Measure[MeasureCount - 1].create_time; 562 | //Measure[MeasureCount].isDispBarLine = false; 563 | } 564 | switch (Command.knd) { 565 | case COMMAND_BRANCHSTART: 566 | BeforeBranchJudgeTime = Measure[MeasureCount].judge_time; 567 | BeforeBranchCreateTime = Measure[MeasureCount].create_time; 568 | BeforeBranchPopTime = Measure[MeasureCount].pop_time; 569 | BeforeBranchBpm = bpm; 570 | BeforeBranchDelay = delay; 571 | BeforeBranchMeasure = measure; 572 | BeforeBranchPreJudge = PreJudge; 573 | BeforeBranchScroll = scroll; 574 | BeforeBranchNextBpm = NextBpm; 575 | BeforeBranchNextMeasure = NextMeasure; 576 | BeforeBranchIsDispBarLine = isDispBarLine; 577 | BeforeBranchFirstMultiMeasure = FirstMultiMeasure; 578 | BeforeBranchIsNoComma = isNoComma; 579 | BeforeBranchNotesCount = NotesCount; 580 | BeforeBranchPercent = percent; 581 | if (tja_cnt == 0) Measure[MeasureCount].judge_time = 0; //ノーツの前に分岐はすぐに判定 582 | break; 583 | case COMMAND_N: 584 | case COMMAND_E: 585 | case COMMAND_M: 586 | bpm = BeforeBranchBpm; 587 | measure = BeforeBranchMeasure; 588 | delay = BeforeBranchDelay; 589 | scroll = BeforeBranchScroll; 590 | NextBpm = BeforeBranchNextBpm; 591 | NextMeasure = BeforeBranchNextMeasure; 592 | Measure[MeasureCount].judge_time = BeforeBranchJudgeTime; 593 | Measure[MeasureCount].create_time = BeforeBranchCreateTime; 594 | Measure[MeasureCount].pop_time = BeforeBranchPopTime; 595 | PreJudge = BeforeBranchPreJudge; 596 | isDispBarLine = BeforeBranchIsDispBarLine; 597 | FirstMultiMeasure =BeforeBranchFirstMultiMeasure; 598 | isNoComma = BeforeBranchIsNoComma; 599 | NotesCount = BeforeBranchNotesCount; 600 | percent = BeforeBranchPercent; 601 | break; 602 | default: 603 | break; 604 | } 605 | } 606 | else { 607 | if (isNoComma == false) PreJudge = Measure[MeasureCount].judge_time; 608 | bpm = NextBpm; 609 | measure = NextMeasure; 610 | delay = 0; 611 | } 612 | 613 | 614 | if (isNoComma == false && NotesCount != 0 && tja_notes[tja_cnt][0] != '#') { //複数行小節の最後の行 615 | 616 | Measure[Measure[MeasureCount].firstmeasure].max_notes = NotesCount + 1; 617 | FirstMultiMeasure = -1; 618 | NotesCount = 0; 619 | 620 | for (int i = 1; i < MeasureCount - Measure[MeasureCount].firstmeasure + 1; i++) { //judge_timeの調整 621 | 622 | if (tja_notes[Measure[MeasureCount].notes][0] != '#') { //複数行小節の最初の小節以外 623 | 624 | Measure[Measure[MeasureCount].firstmeasure + i].judge_time = 625 | Measure[Measure[MeasureCount].firstmeasure + i - 1].judge_time + 626 | (60.0 / Measure[Measure[MeasureCount].firstmeasure + i - 1].bpm * 4 * Measure[Measure[MeasureCount].firstmeasure + i - 1].measure) 627 | * Measure[Measure[MeasureCount].firstmeasure + i - 1].notes_count / Measure[Measure[MeasureCount].firstmeasure].max_notes; //delayはとりあえず放置 628 | 629 | Measure[Measure[MeasureCount].firstmeasure + i].pop_time = Measure[Measure[MeasureCount].firstmeasure + i].judge_time - (60.0 / Measure[Measure[MeasureCount].firstmeasure + i].bpm * 4)*(NOTES_JUDGE_RANGE / (NOTES_AREA)); 630 | Measure[Measure[MeasureCount].firstmeasure + i].create_time = Measure[Measure[MeasureCount].firstmeasure + i].judge_time - (60.0 / Measure[Measure[MeasureCount].firstmeasure + i].bpm * 4)*((1.0/Option.speed)*NOTES_JUDGE_RANGE / (NOTES_AREA*Measure[Measure[MeasureCount].firstmeasure + i].scroll)); 631 | percent = (double)Measure[Measure[MeasureCount].firstmeasure + i].notes_count / (double)Measure[Measure[MeasureCount].firstmeasure].max_notes; 632 | 633 | Measure[Measure[MeasureCount].firstmeasure + i].isDispBarLine = false; //最初の小節は小節線をオフにしない 634 | } 635 | } 636 | 637 | PreJudge = Measure[MeasureCount].judge_time; 638 | } 639 | else if (tja_notes[tja_cnt][0] != '#') { 640 | percent = 1; 641 | } 642 | 643 | 644 | if (isEnd == true) { 645 | break; 646 | } 647 | 648 | tja_cnt++; 649 | MeasureCount++; 650 | } 651 | } 652 | 653 | MeasureMaxNumber = tja_cnt; 654 | 655 | for (int i = 0; i < MeasureMaxNumber; i++) { //次の小節の判定時に発動する命令の調整 656 | 657 | if (Measure[i].command == COMMAND_SECTION) { 658 | int n = i + 1; 659 | while (n <= MeasureMaxNumber && tja_notes[n][0] == '#') n++; 660 | Measure[i].judge_time = Measure[n].judge_time; 661 | } 662 | } 663 | 664 | //基本天井点を計算 665 | 666 | calc_base_score(Measure, tja_notes); 667 | 668 | fclose(fp); 669 | sort_measure_insertion(Measure, MEASURE_MAX); 670 | MainFirstMeasureTime = calc_first_measure_time(); 671 | } 672 | } 673 | 674 | void get_tja_header(TJA_HEADER_T *TJA_Header) { 675 | 676 | *TJA_Header = Current_Header; 677 | } 678 | 679 | void tja_to_notes(bool isDon, bool isKatsu, int count, C2D_Sprite sprites[SPRITES_NUMER]) { 680 | 681 | notes_main(isDon, isKatsu, tja_notes, Measure, count, sprites); 682 | 683 | } 684 | 685 | //コマンドと値を取り出す 686 | void get_command_value(char* buf, COMMAND_T *Command) { 687 | 688 | bool isComment = false; 689 | int comment, space, length; 690 | 691 | if (buf[0] == '#') { 692 | 693 | length = strlen(buf); 694 | comment = 0; 695 | 696 | char* command = (char *)malloc((strlen(buf) + 1)); 697 | char* value = (char *)malloc((strlen(buf) + 1)); 698 | 699 | Command->notes = buf; 700 | 701 | if (strstr(buf, "//") != NULL) { //コメント処理 702 | 703 | comment = strstr(buf, "//") - buf - 1; 704 | strlcpy(command, buf + 1, comment); 705 | isComment = true; 706 | } 707 | 708 | if (strstr(buf, " ") != NULL) { //値処理 709 | 710 | space = strstr(buf, " ") - buf; 711 | 712 | if (space < comment && isComment == true) { //値ありコメントあり 713 | 714 | strlcpy(command, buf + 1, space); 715 | strlcpy(value, buf + 1 + strlen(command), comment - strlen(command) + 1); 716 | 717 | } 718 | else { //値ありコメントなし 719 | strlcpy(command, buf + 1, space); 720 | strlcpy(value, buf + 1 + strlen(command), length - strlen(command)); 721 | } 722 | } 723 | else { //値なし 724 | 725 | //コメントあり 726 | if (isComment == true) strlcpy(command, buf + 1, comment + 1); 727 | //コメントなし 改行あり 728 | else if (strstr(buf, "\n") != NULL) strlcpy(command, buf + 1, length - 2); 729 | //コメントなし 改行なし 730 | else strlcpy(command, buf + 1, length); 731 | 732 | strlcpy(value, "0", 1); 733 | } 734 | 735 | 736 | Command->command_s = command; 737 | Command->value_s = value; 738 | Command->val[0] = 0; 739 | Command->val[1] = 0; 740 | Command->val[2] = 0; 741 | 742 | if (strcmp(command, "START") == 0) Command->knd = COMMAND_START; 743 | else if (strcmp(command, "END") == 0) Command->knd = COMMAND_END; 744 | else if (strcmp(command, "BPMCHANGE") == 0) { 745 | Command->knd = COMMAND_BPMCHANGE; 746 | Command->val[0] = strtod(value, NULL); 747 | } 748 | else if (strcmp(command, "GOGOSTART") == 0) Command->knd = COMMAND_GOGOSTART; 749 | else if (strcmp(command, "GOGOEND") == 0) Command->knd = COMMAND_GOGOEND; 750 | 751 | else if (strcmp(command, "MEASURE") == 0) { 752 | Command->knd = COMMAND_MEASURE; 753 | if (strstr(value, "/") != NULL) { 754 | 755 | int srash = strstr(value, "/") - value; 756 | char *denominator = (char *)malloc((strlen(buf) + 1)), 757 | *molecule = (char *)malloc((strlen(buf) + 1)); 758 | strlcpy(molecule, value + 1, srash); 759 | strlcpy(denominator, value + srash + 1, strlen(buf) - srash); 760 | Command->val[0] = strtod(molecule, NULL) / strtod(denominator, NULL); 761 | free(denominator); 762 | free(molecule); 763 | } 764 | else { 765 | if (strtod(value, NULL) != 0) Command->val[0] = strtod(value, NULL); 766 | else Command->val[0] = 1.0; 767 | } 768 | } 769 | else if (strcmp(command, "SCROLL") == 0) { 770 | Command->knd = COMMAND_SCROLL; 771 | Command->val[0] = strtod(value, NULL); 772 | } 773 | else if (strcmp(command, "DELAY") == 0) { 774 | Command->knd = COMMAND_DELAY; 775 | Command->val[0] = strtod(value, NULL); 776 | } 777 | else if (strcmp(command, "SECTION") == 0) Command->knd = COMMAND_SECTION; 778 | else if (strcmp(command, "BRANCHSTART") == 0) { 779 | Command->knd = COMMAND_BRANCHSTART; 780 | char* tp; 781 | tp = strtok(value, ","); 782 | switch (value[1]) { 783 | case 'r':Command->val[0] = 0; break; //連打 784 | case 'p':Command->val[0] = 1; break; //精度 785 | case 's':Command->val[0] = 2; break; //スコア 786 | default: break; 787 | } 788 | int i = 1; 789 | while ((tp = strtok(NULL, ","))) { 790 | Command->val[i] = strtod(tp, NULL); 791 | i++; 792 | } 793 | } 794 | else if (strcmp(command, "BRANCHEND") == 0) Command->knd = COMMAND_BRANCHEND; 795 | else if (strcmp(command, "N") == 0) Command->knd = COMMAND_N; 796 | else if (strcmp(command, "E") == 0) Command->knd = COMMAND_E; 797 | else if (strcmp(command, "M") == 0) Command->knd = COMMAND_M; 798 | else if (strcmp(command, "LEVELHOLD") == 0) Command->knd = COMMAND_LEVELHOLD; 799 | else if (strcmp(command, "BMSCROLl") == 0) Command->knd = COMMAND_BMSCROLL; 800 | else if (strcmp(command, "HBSCROLL") == 0) Command->knd = COMMAND_HBSCROLL; 801 | else if (strcmp(command, "BARLINEOFF") == 0) Command->knd = COMMAND_BARLINEOFF; 802 | else if (strcmp(command, "BARLINEON") == 0) Command->knd = COMMAND_BARLINEON; 803 | else Command->knd = -1; 804 | 805 | free(command); 806 | free(value); 807 | } 808 | 809 | else Command->knd = -1; 810 | } 811 | 812 | double get_FirstMeasureTime() { 813 | return MainFirstMeasureTime; 814 | } 815 | 816 | int get_MeasureId_From_OriginalId(int id) { 817 | 818 | for (int i = 0; i < MEASURE_MAX; i++) { 819 | 820 | if (Measure[i].original_id == id) return i; 821 | } 822 | return -1; 823 | } 824 | 825 | bool get_isBranch() { 826 | return isBranch; 827 | } -------------------------------------------------------------------------------- /source/option.cpp: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "option.h" 3 | #include "select.h" 4 | #include "main.h" 5 | #include "vorbis.h" 6 | #include 7 | 8 | OPTION_T Option; 9 | json_t *json; 10 | json_error_t error_json; 11 | int option_page = 1,max_option_page = 4; 12 | 13 | //数字キーボードで入力 14 | double input_number_keyboard(int max_digits,bool isDot,bool isMinus) { //最大桁数、少数、マイナス 15 | 16 | SwkbdState swkbd; 17 | swkbdInit(&swkbd, SWKBD_TYPE_NUMPAD, 1, max_digits); 18 | //swkbdSetPasswordMode(&swkbd, SWKBD_PASSWORD_HIDE_DELAY); 19 | swkbdSetValidation(&swkbd, SWKBD_ANYTHING, 0, 0); 20 | swkbdSetFeatures(&swkbd, SWKBD_FIXED_WIDTH); 21 | if (isDot == true && isMinus == false) swkbdSetNumpadKeys(&swkbd, L'.', 0); 22 | if (isDot == false && isMinus == true) swkbdSetNumpadKeys(&swkbd, L'-', 0); 23 | if (isDot == true && isMinus==true) swkbdSetNumpadKeys(&swkbd, L'.', L'-'); 24 | swkbdInputText(&swkbd, get_buffer(), BUFFER_SIZE); 25 | return atof(get_buffer()); 26 | } 27 | 28 | void init_button_mapping() { 29 | 30 | Option.KEY_A = KEY_KATSU; 31 | Option.KEY_B = KEY_DON; 32 | Option.KEY_Y = KEY_DON; 33 | Option.KEY_X = KEY_KATSU; 34 | Option.KEY_R = KEY_KATSU; 35 | Option.KEY_L = KEY_KATSU; 36 | Option.KEY_ZR = KEY_KATSU; 37 | Option.KEY_ZL = KEY_KATSU; 38 | Option.KEY_DRIGHT = KEY_DON; 39 | Option.KEY_DDOWN = KEY_DON; 40 | Option.KEY_DLEFT = KEY_KATSU; 41 | Option.KEY_DUP = KEY_KATSU; 42 | Option.KEY_CPAD_RIGHT = KEY_DON; 43 | Option.KEY_CPAD_DOWN = KEY_DON; 44 | Option.KEY_CPAD_LEFT = KEY_KATSU; 45 | Option.KEY_CPAD_UP = KEY_KATSU; 46 | Option.KEY_CSTICK_RIGHT = KEY_KATSU; 47 | Option.KEY_CSTICK_DOWN = KEY_DON; 48 | Option.KEY_CSTICK_LEFT = KEY_DON; 49 | Option.KEY_CSTICK_UP = KEY_KATSU; 50 | } 51 | 52 | void draw_button_mapping_icon(double x,double y,int key, C2D_Sprite sprites[SPRITES_NUMER]) { 53 | 54 | C2D_ImageTint Tint; 55 | C2D_AlphaImageTint(&Tint, 0.5); 56 | 57 | int sprite; 58 | bool isNotes = true; 59 | switch (key) { 60 | case KEY_NONE: 61 | default: 62 | isNotes = false; 63 | break; 64 | case KEY_DON: 65 | sprite = SPRITE_DON; 66 | break; 67 | case KEY_KATSU: 68 | sprite = SPRITE_KATSU; 69 | break; 70 | } 71 | 72 | if (isNotes == true) { 73 | C2D_SpriteSetPos(&sprites[sprite], x, y); 74 | C2D_DrawSpriteTinted(&sprites[sprite], &Tint); 75 | } 76 | } 77 | 78 | void switch_button_mapping(int *key) { 79 | 80 | switch (*key) { 81 | case KEY_NONE: 82 | default: 83 | *key = KEY_DON; 84 | break; 85 | case KEY_DON: 86 | *key = KEY_KATSU; 87 | break; 88 | case KEY_KATSU: 89 | *key = KEY_NONE; 90 | break; 91 | } 92 | } 93 | 94 | void adjust_judge_range() { 95 | 96 | if (Option.judge_range_perfect <= 0) Option.judge_range_perfect = DEFAULT_JUDGE_RANGE_PERFECT; 97 | if (Option.judge_range_nice <= 0) Option.judge_range_nice = DEFAULT_JUDGE_RANGE_NICE; 98 | if (Option.judge_range_bad <= 0) Option.judge_range_bad = DEFAULT_JUDGE_RANGE_BAD; 99 | } 100 | 101 | void calc_option_page(u16 px, u16 py, unsigned int key) { 102 | 103 | float width, height,x,y; 104 | 105 | if (option_page > 1) { 106 | x = 30, y = 205; 107 | draw_option_text(x, y, "←", true, &width, &height, 2.5, 1.5); 108 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 109 | if (option_page != 1) option_page--; 110 | } 111 | } 112 | if (option_page < max_option_page) { 113 | x = 230, y = 205; 114 | draw_option_text(x, y, "→", true, &width, &height, 2.5, 1.5); 115 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 116 | if (option_page < max_option_page) option_page++; 117 | } 118 | } 119 | snprintf(get_buffer(), BUFFER_SIZE, "%d/%d", option_page,max_option_page); 120 | draw_option_text(145, 218, get_buffer(), true, &width, &height); 121 | } 122 | 123 | void draw_option(u16 px, u16 py, unsigned int key, C2D_Sprite sprites[SPRITES_NUMER]) { 124 | 125 | float width,height,x,y; 126 | int XSense=65, YSense=30,XCnt = 0,YCnt = 1,gap = 25; 127 | int x2, y2, key_interval = 30; 128 | 129 | switch (option_page) { 130 | 131 | case 1: 132 | snprintf(get_buffer(), BUFFER_SIZE, "ver%s", VERSION); 133 | draw_option_text(240, 0, get_buffer(), true, &width, &height); 134 | //オート 135 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 136 | draw_option_text(x, y, Text[Option.lang][TEXT_AUTO], true, &width, &height); 137 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 138 | draw_option_text(x, y, Text[Option.lang][TEXT_OFF], Option.isAuto == false, &width, &height); 139 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.isAuto = false; 140 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 141 | draw_option_text(x, y, Text[Option.lang][TEXT_ON], Option.isAuto == true, &width, &height); 142 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.isAuto = true; 143 | XCnt = 0, YCnt++; 144 | 145 | //はやさ 146 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 147 | draw_option_text(x, y, Text[Option.lang][TEXT_SPEED], true, &width, &height); 148 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 149 | draw_option_text(x, y, Text[Option.lang][TEXT_X1], Option.speed == 1.0, &width, &height); 150 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.speed = 1.0; 151 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 152 | draw_option_text(x, y, Text[Option.lang][TEXT_X2], Option.speed == 2.0, &width, &height); 153 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.speed = 2.0; 154 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 155 | draw_option_text(x, y, Text[Option.lang][TEXT_X3], Option.speed == 3.0, &width, &height); 156 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.speed = 3.0; 157 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 158 | draw_option_text(x, y, Text[Option.lang][TEXT_X4], Option.speed == 4.0, &width, &height); 159 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.speed = 4.0; 160 | XCnt = 0, YCnt++; 161 | 162 | //ステルス 163 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 164 | draw_option_text(x, y, Text[Option.lang][TEXT_STELTH], true, &width, &height); 165 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 166 | draw_option_text(x, y, Text[Option.lang][TEXT_OFF], Option.isStelth == false, &width, &height); 167 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.isStelth = false; 168 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 169 | draw_option_text(x, y, Text[Option.lang][TEXT_ON], Option.isStelth == true, &width, &height); 170 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.isStelth = true; 171 | XCnt = 0, YCnt++; 172 | 173 | //あべこべ 174 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 175 | draw_option_text(x, y, Text[Option.lang][TEXT_SWAP], true, &width, &height); 176 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 177 | draw_option_text(x, y, Text[Option.lang][TEXT_OFF], Option.isSwap == false, &width, &height); 178 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.isSwap = false; 179 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 180 | draw_option_text(x, y, Text[Option.lang][TEXT_ON], Option.isSwap == true, &width, &height); 181 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.isSwap = true; 182 | XCnt = 0, YCnt++; 183 | 184 | //ランダム 185 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 186 | draw_option_text(x, y, Text[Option.lang][TEXT_RANDOM], true, &width, &height); 187 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 188 | draw_option_text(x, y, Text[Option.lang][TEXT_OFF], Option.random == 0, &width, &height); 189 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.random = 0; 190 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 191 | draw_option_text(x, y, Text[Option.lang][TEXT_R25], Option.random == 0.25, &width, &height); 192 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.random = 0.25; 193 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 194 | draw_option_text(x, y, Text[Option.lang][TEXT_R50], Option.random == 0.5, &width, &height); 195 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.random = 0.5; 196 | XCnt = 0, YCnt++; 197 | 198 | //言語 199 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 200 | draw_option_text(x, y, Text[Option.lang][TEXT_LANG], true, &width, &height); 201 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 202 | draw_option_text(x, y, Text[Option.lang][TEXT_JP], Option.lang == LANG_JP, &width, &height); 203 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.lang = LANG_JP; 204 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 205 | draw_option_text(x, y, Text[Option.lang][TEXT_EN], Option.lang == LANG_EN, &width, &height); 206 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.lang = LANG_EN; 207 | x = XSense * XCnt + gap+10, y = YSense * YCnt, XCnt++; 208 | draw_option_text(x, y, Text[Option.lang][TEXT_ES], Option.lang == LANG_ES, &width, &height); 209 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.lang = LANG_ES; 210 | XCnt = 0, YCnt++; 211 | break; 212 | 213 | case 2: 214 | XSense = 65, YSense = 30, XCnt = 0, YCnt = 1, gap = 100; 215 | //バッファ 216 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 217 | draw_option_text(x, y, Text[Option.lang][TEXT_BUFFERSIZE], true, &width, &height); 218 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 219 | snprintf(get_buffer(), BUFFER_SIZE, "%d", get_buffer_size()); 220 | draw_option_text(x, y, get_buffer(), true, &width, &height); 221 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 222 | Option.buffer_size = (int)input_number_keyboard(5, false,false); 223 | if (Option.buffer_size < 1000) Option.buffer_size = 1000; 224 | put_buffer_size(Option.buffer_size); 225 | } 226 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 227 | draw_option_text(x, y, Text[Option.lang][TEXT_RESET], true, &width, &height); 228 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 229 | Option.buffer_size = DEFAULT_BUFFER_SIZE; 230 | put_buffer_size(Option.buffer_size); 231 | } 232 | XCnt = 0, YCnt++; 233 | 234 | //はやさ 235 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 236 | draw_option_text(x, y, Text[Option.lang][TEXT_SPEED], true, &width, &height); 237 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 238 | snprintf(get_buffer(), BUFFER_SIZE, "%.2f", Option.speed); 239 | draw_option_text(x, y, get_buffer(), true, &width, &height); 240 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 241 | Option.speed = input_number_keyboard(5, true,false); 242 | if (Option.speed > 10.0) Option.speed = 10.0; 243 | if (Option.speed < 1.0) Option.speed = 1.0; 244 | } 245 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 246 | draw_option_text(x, y, Text[Option.lang][TEXT_RESET], true, &width, &height); 247 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.speed = 1.0; 248 | XCnt = 0, YCnt++; 249 | 250 | //offset 251 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 252 | draw_option_text(x, y, "offset", true, &width, &height); 253 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 254 | if (Option.offset == 0)snprintf(get_buffer(), BUFFER_SIZE, "±%.2f", Option.offset); 255 | else if (Option.offset > 0)snprintf(get_buffer(), BUFFER_SIZE, "+%.2f", Option.offset); 256 | else snprintf(get_buffer(), BUFFER_SIZE, "%.2f", Option.offset); 257 | draw_option_text(x, y, get_buffer(), true, &width, &height); 258 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 259 | Option.offset = input_number_keyboard(5, true,true); 260 | } 261 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 262 | draw_option_text(x, y, Text[Option.lang][TEXT_RESET], true, &width, &height); 263 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.offset = 0; 264 | XCnt = 0, YCnt++; 265 | 266 | //fps 267 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 268 | draw_option_text(x, y, Text[Option.lang][TEXT_DISP_FPS], true, &width, &height); 269 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 270 | draw_option_text(x, y, Text[Option.lang][TEXT_OFF], Option.dispFps == false, &width, &height); 271 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.dispFps = false; 272 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 273 | draw_option_text(x, y, Text[Option.lang][TEXT_ON], Option.dispFps == true, &width, &height); 274 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.dispFps = true; 275 | XCnt = 0, YCnt++; 276 | break; 277 | 278 | case 3: 279 | XSense = 65, YSense = 30, XCnt = 0, YCnt = 1, gap = 100; 280 | //良 281 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 282 | draw_option_text(x, y, Text[Option.lang][TEXT_PERFECT], true, &width, &height); 283 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 284 | snprintf(get_buffer(), BUFFER_SIZE, "%.3f", Option.judge_range_perfect); 285 | draw_option_text(x, y, get_buffer(), true, &width, &height); 286 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 287 | Option.judge_range_perfect = input_number_keyboard(5, true, false); 288 | adjust_judge_range(); 289 | } 290 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 291 | draw_option_text(x, y, Text[Option.lang][TEXT_RESET], true, &width, &height); 292 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.judge_range_perfect = DEFAULT_JUDGE_RANGE_PERFECT; 293 | XCnt = 0, YCnt++; 294 | 295 | //可 296 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 297 | draw_option_text(x, y, Text[Option.lang][TEXT_NICE], true, &width, &height); 298 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 299 | snprintf(get_buffer(), BUFFER_SIZE, "%.3f", Option.judge_range_nice); 300 | draw_option_text(x, y, get_buffer(), true, &width, &height); 301 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 302 | Option.judge_range_nice = input_number_keyboard(5, true, false); 303 | adjust_judge_range(); 304 | } 305 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 306 | draw_option_text(x, y, Text[Option.lang][TEXT_RESET], true, &width, &height); 307 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.judge_range_nice = DEFAULT_JUDGE_RANGE_NICE; 308 | XCnt = 0, YCnt++; 309 | 310 | //不可 311 | x = XSense * XCnt, y = YSense * YCnt, XCnt++; 312 | draw_option_text(x, y, Text[Option.lang][TEXT_BAD], true, &width, &height); 313 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 314 | snprintf(get_buffer(), BUFFER_SIZE, "%.3f", Option.judge_range_bad); 315 | draw_option_text(x, y, get_buffer(), true, &width, &height); 316 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) { 317 | Option.judge_range_bad = input_number_keyboard(5, true, false); 318 | adjust_judge_range(); 319 | } 320 | x = XSense * XCnt + gap, y = YSense * YCnt, XCnt++; 321 | draw_option_text(x, y, Text[Option.lang][TEXT_RESET], true, &width, &height); 322 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) Option.judge_range_bad = DEFAULT_JUDGE_RANGE_BAD; 323 | XCnt = 0, YCnt++; 324 | break; 325 | 326 | case 4: 327 | //ボタンマッピング 328 | 329 | draw_option_text(-1, 25, Text[Option.lang][TEXT_BUTTON_MAPPING], true, &width, &height); 330 | x = 130, y = 120; 331 | draw_option_text(-1, y, Text[Option.lang][TEXT_RESET], true, &width, &height); 332 | x = BOTTOM_WIDTH / 2 - width / 2; 333 | if ((y < py && y + height > py && x < px && x + width > px) && key & KEY_TOUCH) init_button_mapping(); 334 | 335 | //ABYX 336 | x = 280, y = 150; 337 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_A, sprites); 338 | draw_option_text(x, y, "A", true, &width, &height); 339 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 340 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_A); 341 | 342 | x -= key_interval, y += key_interval; 343 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_B, sprites); 344 | draw_option_text(x, y, "B", true, &width, &height); 345 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 346 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_B); 347 | 348 | x -= key_interval, y -= key_interval; 349 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_Y, sprites); 350 | draw_option_text(x, y, "Y", true, &width, &height); 351 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 352 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_Y); 353 | 354 | x += key_interval, y -= key_interval; 355 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_X, sprites); 356 | draw_option_text(x, y, "X", true, &width, &height); 357 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 358 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_X); 359 | 360 | //Dパット(十字キー) 361 | C2D_DrawRectangle(47, 130, 0, 30, 80, C2D_Color32f(1, 1, 1, 0.4), C2D_Color32f(1, 1, 1, 0.4), C2D_Color32f(1, 1, 1, 0.4), C2D_Color32f(1, 1, 1, 0.4)); 362 | C2D_DrawRectangle(22, 155, 0, 80, 30, C2D_Color32f(1, 1, 1, 0.4), C2D_Color32f(1, 1, 1, 0.4), C2D_Color32f(1, 1, 1, 0.4), C2D_Color32f(1, 1, 1, 0.4)); 363 | key_interval = 25; 364 | x = 80, y = 160; 365 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_DRIGHT, sprites); 366 | draw_option_text(x, y, "ー", true, &width, &height); 367 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 368 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_DRIGHT); 369 | 370 | x -= key_interval, y += key_interval; 371 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_DDOWN, sprites); 372 | draw_option_text(x, y, "|", true, &width, &height); 373 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 374 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_DDOWN); 375 | 376 | x -= key_interval, y -= key_interval; 377 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_DLEFT, sprites); 378 | draw_option_text(x, y, "ー", true, &width, &height); 379 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 380 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_DLEFT); 381 | 382 | x += key_interval, y -= key_interval; 383 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_DUP, sprites); 384 | draw_option_text(x, y, "|", true, &width, &height); 385 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 386 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_DUP); 387 | 388 | //CPAD 389 | C2D_DrawCircleSolid(60, 80, 0,35, C2D_Color32f(1, 1, 1, 0.4)); 390 | key_interval = 25; 391 | x = 80, y = 70; 392 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CPAD_RIGHT, sprites); 393 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 394 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CPAD_RIGHT); 395 | 396 | x -= key_interval, y += key_interval; 397 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CPAD_DOWN, sprites); 398 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 399 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CPAD_DOWN); 400 | 401 | x -= key_interval, y -= key_interval; 402 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CPAD_LEFT, sprites); 403 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 404 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CPAD_LEFT); 405 | 406 | x += key_interval, y -= key_interval; 407 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CPAD_UP, sprites); 408 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 409 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CPAD_UP); 410 | 411 | //Cスティック 412 | C2D_DrawCircleSolid(230, 80, 0, 15, C2D_Color32f(1, 1, 1, 0.4)); 413 | key_interval = 20; 414 | x = 245, y = 70; 415 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CSTICK_RIGHT, sprites); 416 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 417 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CSTICK_RIGHT); 418 | 419 | x -= key_interval, y += key_interval; 420 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CSTICK_DOWN, sprites); 421 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 422 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CSTICK_DOWN); 423 | 424 | x -= key_interval, y -= key_interval; 425 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CSTICK_LEFT, sprites); 426 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 427 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CSTICK_LEFT); 428 | 429 | x += key_interval, y -= key_interval; 430 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_CSTICK_UP, sprites); 431 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 432 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_CSTICK_UP); 433 | 434 | //L,ZL,ZR,R 435 | x = 20, y = 10; 436 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_L, sprites); 437 | draw_option_text(x, y, "L", true, &width, &height); 438 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 439 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_L); 440 | 441 | x += 40; 442 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_ZL, sprites); 443 | draw_option_text(x-3, y, "ZL", true, &width, &height); 444 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 445 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_ZL); 446 | 447 | x = 250; 448 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_ZR, sprites); 449 | draw_option_text(x - 3, y, "ZR", true, &width, &height); 450 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 451 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_ZR); 452 | 453 | x += 40; 454 | draw_button_mapping_icon(x + 6, y + 10, Option.KEY_R, sprites); 455 | draw_option_text(x, y, "R", true, &width, &height); 456 | width = 26, height = 26, x2 = x - 5, y2 = y - 5; 457 | if ((y2 < py && y2 + height > py && x2 < px && x2 + width > px) && key & KEY_TOUCH) switch_button_mapping(&Option.KEY_R); 458 | break; 459 | 460 | default: 461 | break; 462 | } 463 | 464 | calc_option_page(px,py,key); 465 | } 466 | 467 | int get_lang() { 468 | return Option.lang; 469 | } 470 | 471 | void toggle_auto() { 472 | Option.isAuto = !Option.isAuto; 473 | } 474 | 475 | void init_option() { 476 | 477 | Option.isAuto = false; 478 | Option.isStelth = false; 479 | Option.dispFps = false; 480 | Option.random = 0; 481 | Option.speed = 1.0; 482 | Option.isSwap = false; 483 | Option.lang = LANG_JP; 484 | Option.buffer_size = DEFAULT_BUFFER_SIZE; 485 | Option.offset = 0; 486 | Option.judge_range_perfect = DEFAULT_JUDGE_RANGE_PERFECT; 487 | Option.judge_range_nice = DEFAULT_JUDGE_RANGE_NICE; 488 | Option.judge_range_bad = DEFAULT_JUDGE_RANGE_BAD; 489 | 490 | init_button_mapping(); 491 | 492 | option_page = 1; 493 | } 494 | 495 | void save_option() { 496 | 497 | json_object_set(json, "lang", json_integer(Option.lang)); 498 | json_object_set(json, "buffer_size", json_integer(Option.buffer_size)); 499 | json_object_set(json, "isAuto", json_boolean(Option.isAuto)); 500 | json_object_set(json, "isStelth", json_boolean(Option.isStelth)); 501 | json_object_set(json, "isSwap", json_boolean(Option.isSwap)); 502 | json_object_set(json, "dispFps", json_boolean(Option.dispFps)); 503 | json_object_set(json, "random", json_real(Option.random)); 504 | json_object_set(json, "speed", json_real(Option.speed)); 505 | json_object_set(json, "offset", json_real(Option.offset)); 506 | json_object_set(json, "KEY_A", json_integer(Option.KEY_A)); 507 | json_object_set(json, "KEY_B", json_integer(Option.KEY_B)); 508 | json_object_set(json, "KEY_X", json_integer(Option.KEY_X)); 509 | json_object_set(json, "KEY_Y", json_integer(Option.KEY_Y)); 510 | json_object_set(json, "KEY_R", json_integer(Option.KEY_R)); 511 | json_object_set(json, "KEY_ZR", json_integer(Option.KEY_ZR)); 512 | json_object_set(json, "KEY_L", json_integer(Option.KEY_L)); 513 | json_object_set(json, "KEY_ZL", json_integer(Option.KEY_ZL)); 514 | json_object_set(json, "KEY_DUP", json_integer(Option.KEY_DUP)); 515 | json_object_set(json, "KEY_DDOWN", json_integer(Option.KEY_DDOWN)); 516 | json_object_set(json, "KEY_DRIGHT", json_integer(Option.KEY_DRIGHT)); 517 | json_object_set(json, "KEY_DLEFT", json_integer(Option.KEY_DLEFT)); 518 | json_object_set(json, "KEY_CPAD_UP", json_integer(Option.KEY_CPAD_UP)); 519 | json_object_set(json, "KEY_CPAD_DOWN", json_integer(Option.KEY_CPAD_DOWN)); 520 | json_object_set(json, "KEY_CPAD_RIGHT", json_integer(Option.KEY_CPAD_RIGHT)); 521 | json_object_set(json, "KEY_CPAD_LEFT", json_integer(Option.KEY_CPAD_LEFT)); 522 | json_object_set(json, "KEY_CSTICK_UP", json_integer(Option.KEY_CSTICK_UP)); 523 | json_object_set(json, "KEY_CSTICK_DOWN", json_integer(Option.KEY_CSTICK_DOWN)); 524 | json_object_set(json, "KEY_CSTICK_RIGHT", json_integer(Option.KEY_CSTICK_RIGHT)); 525 | json_object_set(json, "KEY_CSTICK_LEFT", json_integer(Option.KEY_CSTICK_LEFT)); 526 | json_object_set(json, "judge_range_perfect", json_integer(round(Option.judge_range_perfect * 1000))); 527 | json_object_set(json, "judge_range_nice", json_integer(round(Option.judge_range_nice * 1000))); 528 | json_object_set(json, "judge_range_bad", json_integer(round(Option.judge_range_bad * 1000))); 529 | 530 | json_dump_file(json, SETTING_FILE, 0); 531 | } 532 | 533 | void load_option() { 534 | 535 | init_option(); 536 | 537 | json = json_load_file(SETTING_FILE, 0, &error_json); 538 | 539 | if (json != NULL){ 540 | 541 | Option.lang = json_integer_value(json_object_get(json, "lang")); 542 | Option.buffer_size = json_integer_value(json_object_get(json, "buffer_size")); 543 | Option.isAuto = json_boolean_value(json_object_get(json, "isAuto")); 544 | Option.isStelth = json_boolean_value(json_object_get(json, "isStelth")); 545 | Option.isSwap = json_boolean_value(json_object_get(json, "isSwap")); 546 | Option.dispFps = json_boolean_value(json_object_get(json, "dispFps")); 547 | Option.random = json_real_value(json_object_get(json, "random")); 548 | Option.speed = json_real_value(json_object_get(json, "speed")); 549 | Option.offset = json_real_value(json_object_get(json, "offset")); 550 | Option.KEY_A = json_integer_value(json_object_get(json, "KEY_A")); 551 | Option.KEY_B = json_integer_value(json_object_get(json, "KEY_B")); 552 | Option.KEY_X = json_integer_value(json_object_get(json, "KEY_X")); 553 | Option.KEY_Y = json_integer_value(json_object_get(json, "KEY_Y")); 554 | Option.KEY_R = json_integer_value(json_object_get(json, "KEY_R")); 555 | Option.KEY_ZR = json_integer_value(json_object_get(json, "KEY_ZR")); 556 | Option.KEY_L = json_integer_value(json_object_get(json, "KEY_L")); 557 | Option.KEY_ZL = json_integer_value(json_object_get(json, "KEY_ZL")); 558 | Option.KEY_DUP = json_integer_value(json_object_get(json, "KEY_DUP")); 559 | Option.KEY_DDOWN = json_integer_value(json_object_get(json, "KEY_DDOWN")); 560 | Option.KEY_DRIGHT = json_integer_value(json_object_get(json, "KEY_DRIGHT")); 561 | Option.KEY_DLEFT = json_integer_value(json_object_get(json, "KEY_DLEFT")); 562 | Option.KEY_CPAD_UP = json_integer_value(json_object_get(json, "KEY_CPAD_UP")); 563 | Option.KEY_CPAD_DOWN = json_integer_value(json_object_get(json, "KEY_CPAD_DOWN")); 564 | Option.KEY_CPAD_RIGHT = json_integer_value(json_object_get(json, "KEY_CPAD_RIGHT")); 565 | Option.KEY_CPAD_LEFT = json_integer_value(json_object_get(json, "KEY_CPAD_LEFT")); 566 | Option.KEY_CSTICK_UP = json_integer_value(json_object_get(json, "KEY_CSTICK_UP")); 567 | Option.KEY_CSTICK_DOWN = json_integer_value(json_object_get(json, "KEY_CSTICK_DOWN")); 568 | Option.KEY_CSTICK_RIGHT = json_integer_value(json_object_get(json, "KEY_CSTICK_RIGHT")); 569 | Option.KEY_CSTICK_LEFT = json_integer_value(json_object_get(json, "KEY_CSTICK_LEFT")); 570 | Option.judge_range_perfect = (double)json_integer_value(json_object_get(json, "judge_range_perfect"))/1000; 571 | Option.judge_range_nice = (double)json_integer_value(json_object_get(json, "judge_range_nice"))/1000; 572 | Option.judge_range_bad = (double)json_integer_value(json_object_get(json, "judge_range_bad"))/1000; 573 | 574 | adjust_judge_range(); 575 | } 576 | if (json == NULL) { //開けなかった時 577 | json = json_pack("{}"); //ファイル空の時はこれしないとセットできなくなる 578 | save_option(); //書き込み 579 | } 580 | } 581 | 582 | void exit_option() { 583 | 584 | save_option(); 585 | json_decref(json); 586 | } 587 | 588 | void get_option(OPTION_T *TMP) { 589 | 590 | TMP->isAuto = Option.isAuto; 591 | TMP->isStelth = Option.isStelth; 592 | TMP->random = Option.random; 593 | TMP->speed = Option.speed; 594 | TMP->offset = Option.offset; 595 | TMP->isSwap = Option.isSwap; 596 | TMP->lang = Option.lang; 597 | TMP->buffer_size = Option.buffer_size; 598 | TMP->dispFps = Option.dispFps; 599 | TMP->KEY_A = Option.KEY_A; 600 | TMP->KEY_B = Option.KEY_B; 601 | TMP->KEY_Y = Option.KEY_Y; 602 | TMP->KEY_X = Option.KEY_X; 603 | TMP->KEY_R = Option.KEY_R; 604 | TMP->KEY_ZR = Option.KEY_ZR; 605 | TMP->KEY_L = Option.KEY_L; 606 | TMP->KEY_ZL = Option.KEY_ZL; 607 | TMP->KEY_DRIGHT = Option.KEY_DRIGHT; 608 | TMP->KEY_DLEFT= Option.KEY_DLEFT; 609 | TMP->KEY_DUP = Option.KEY_DUP; 610 | TMP->KEY_DDOWN = Option.KEY_DDOWN; 611 | TMP->KEY_CPAD_RIGHT = Option.KEY_CPAD_RIGHT; 612 | TMP->KEY_CPAD_LEFT = Option.KEY_CPAD_LEFT; 613 | TMP->KEY_CPAD_UP = Option.KEY_CPAD_UP; 614 | TMP->KEY_CPAD_DOWN = Option.KEY_CPAD_DOWN; 615 | TMP->KEY_CSTICK_RIGHT = Option.KEY_CSTICK_RIGHT; 616 | TMP->KEY_CSTICK_LEFT = Option.KEY_CSTICK_LEFT; 617 | TMP->KEY_CSTICK_UP = Option.KEY_CSTICK_UP; 618 | TMP->KEY_CSTICK_DOWN = Option.KEY_CSTICK_DOWN; 619 | TMP->judge_range_perfect = Option.judge_range_perfect; 620 | TMP->judge_range_nice = Option.judge_range_nice; 621 | TMP->judge_range_bad = Option.judge_range_bad; 622 | } --------------------------------------------------------------------------------