@@ -12,118 +12,103 @@ use std::{fs, string::String};
1212/// デフォルト画像URL
1313const IMAGE_DEFAULT : & str = "https://www.dustloop.com/wiki/images/5/54/GGST_Logo_Sparkly.png" ;
1414
15- /// 指定されたキャラクターの技データを詳細に表示する非同期コマンド
16- ///
17- /// # 概要
18- /// 入力されたキャラクター名(または愛称)と技名(入力またはエイリアス)から、
19- /// キャラクター情報ファイルおよび画像リンクファイルを読み込み、
20- /// 対象の技データを抽出し、Discord用の埋め込みメッセージとして表示する。
15+ /// キャラクターデータを読み込む関数
2116///
2217/// # 引数
23- /// * `ctx` - コマンド実行コンテキスト(Discordとの通信に利用)
24- /// * `character` - キャラクター名または愛称(2文字以上必須)
25- /// * `character_move` - 技名、入力、またはエイリアス(2文字以上必須)
18+ /// * `character` - ユーザーが入力したキャラクター名
19+ /// * `ctx` - コマンドコンテキスト
2620///
2721/// # 戻り値
28- /// 正常終了時は `Ok(())` を返し、エラー発生時は `Err(Error)` を返す。
29- ///
30- /// # 例
31- /// ```rust,no_run
32- /// # async fn example(ctx: Context<'_>) -> Result<(), Error> {
33- /// advanced(ctx, "Sol".to_string(), "236H".to_string()).await?;
34- /// # Ok(()) }
35- /// ```
36- ///
37- /// # 注意
38- /// この関数は非同期関数であるため、呼び出し時に `.await` が必要。
39- #[ poise:: command( prefix_command, slash_command) ]
40- pub async fn advanced (
41- ctx : Context < ' _ > ,
42- #[ min_length = 2 ]
43- #[ description = "キャラクター名または愛称" ]
44- character : String ,
45- #[ min_length = 2 ]
46- #[ rename = "move" ]
47- #[ description = "技名、入力、またはエイリアス" ]
48- character_move : String ,
49- ) -> Result < ( ) , AppError > {
50- // コマンド引数の表示 引数確認用
51- println ! (
52- "{}" ,
53- ( "Command Args: '" . to_owned( ) + & character + ", " + & character_move + "'" ) . purple( )
54- ) ;
55-
56- // 埋め込み画像用変数の初期化 初期値はデフォルト画像URL
57- let mut embed_image = IMAGE_DEFAULT . to_string ( ) ;
58-
59- // 入力チェックの実施 各種前提条件チェック
60- if ( check:: adaptive_check (
61- ctx,
62- check:: CheckOptions {
63- data_folder : true ,
64- nicknames_json : true ,
65- character_folders : true ,
66- character_jsons : true ,
67- character_images : true ,
68- } ,
69- )
70- . await )
71- . is_err ( )
72- {
73- return Ok ( ( ) ) ;
74- }
75-
22+ /// 成功時は正式なキャラクター名、失敗時はエラー
23+ async fn load_character_data ( character : & str , ctx : & Context < ' _ > ) -> Result < String , AppError > {
7624 // キャラクター名の正規化 入力に基づく正式名称の取得
77- let character_arg_altered = match find:: find_character ( & character) . await {
25+ let character_arg_altered = match find:: find_character ( & character. to_string ( ) ) . await {
7826 Ok ( character_arg_altered) => character_arg_altered, // 正式名称取得
7927 Err ( err) => {
8028 ctx. say ( err. to_string ( ) ) . await ?; // エラーメッセージ送信
8129 println ! ( "{}" , ( "Error: " . to_owned( ) + & err. to_string( ) ) . red( ) ) ;
82- return Ok ( ( ) ) ; // 処理中断
30+ return Err ( AppError :: CharacterNotFound ( err . to_string ( ) ) ) ; // 処理中断
8331 }
8432 } ;
8533
34+ Ok ( character_arg_altered)
35+ }
36+
37+ /// 技情報と画像データを読み込む関数
38+ ///
39+ /// # 引数
40+ /// * `character_arg_altered` - 正式なキャラクター名
41+ /// * `character_move` - ユーザーが入力した技名
42+ /// * `ctx` - コマンドコンテキスト
43+ ///
44+ /// # 戻り値
45+ /// 成功時は (技情報, 画像URL) のタプル、失敗時はエラー
46+ async fn find_move_and_images (
47+ character_arg_altered : & str ,
48+ character_move : & str ,
49+ ctx : & Context < ' _ > ,
50+ ) -> Result < ( MoveInfo , String ) , AppError > {
8651 // JSONファイルパスの組み立て キャラクター情報ファイルのパス生成
8752 let char_file_path =
88- "data/" . to_owned ( ) + & character_arg_altered + "/" + & character_arg_altered + ".json" ;
53+ "data/" . to_owned ( ) + character_arg_altered + "/" + character_arg_altered + ".json" ;
8954 // JSONファイルの読み込み キャラクター情報の取得
9055 let char_file_data = fs:: read_to_string ( char_file_path)
91- . expect ( & ( "\n Failed to read '" . to_owned ( ) + & character_arg_altered + ".json" + "' file." ) ) ;
56+ . expect ( & ( "\n Failed to read '" . to_owned ( ) + character_arg_altered + ".json" + "' file." ) ) ;
9257
9358 // JSON文字列のデシリアライズ 技情報の構造体へ変換
9459 let moves_info = serde_json:: from_str :: < Vec < MoveInfo > > ( & char_file_data) . unwrap ( ) ;
9560
9661 // JSON読み込み成功の表示 確認メッセージ出力
9762 println ! (
9863 "{}" ,
99- ( "Successfully read '" . to_owned( ) + & character_arg_altered + ".json' file." ) . green( )
64+ ( "Successfully read '" . to_owned( ) + character_arg_altered + ".json' file." ) . green( )
10065 ) ;
10166
10267 // 画像リンク用JSONファイルのパス組み立て 画像情報ファイルの指定
10368 let image_links = fs:: read_to_string (
104- "data/" . to_owned ( ) + & character_arg_altered + "/images.json" ,
69+ "data/" . to_owned ( ) + character_arg_altered + "/images.json" ,
10570 )
10671 . expect (
107- & ( "\n Failed to read 'data/" . to_owned ( ) + & character_arg_altered + "'/images.json' file." ) ,
72+ & ( "\n Failed to read 'data/" . to_owned ( ) + character_arg_altered + "'/images.json' file." ) ,
10873 ) ;
10974
11075 // 画像リンクJSONのデシリアライズ 画像リンク情報の構造体へ変換
11176 let image_links = serde_json:: from_str :: < Vec < ImageLinks > > ( & image_links) . unwrap ( ) ;
77+
78+ // 技インデックス検索
79+ let move_index = match find:: find_move_index (
80+ & character_arg_altered. to_string ( ) ,
81+ character_move. to_string ( ) ,
82+ & moves_info,
83+ )
84+ . await
85+ {
86+ Ok ( index) => index,
87+ Err ( err) => {
88+ ctx. say ( err. to_string ( ) + "\n View the moves of a character by executing `/moves`." )
89+ . await ?;
90+ println ! ( "{}" , ( "Error: " . to_owned( ) + & err. to_string( ) ) . red( ) ) ;
91+ return Err ( AppError :: MoveNotFound ( err. to_string ( ) ) ) ;
92+ }
93+ } ;
94+
11295 // 対象技情報の取得 入力に対応する技データの抽出
113- let move_info = & moves_info
114- [ find:: find_move_index ( & character_arg_altered, character_move, & moves_info) . await ?] ;
96+ let move_info = moves_info[ move_index] . clone ( ) ;
11597
11698 // 対象技の読み込み成功の表示 確認メッセージ出力
11799 println ! (
118100 "{}" ,
119101 ( "Successfully read move '" . to_owned( )
120- + & move_info. input. to_string ( )
102+ + & move_info. input
121103 + "' in '"
122- + & character_arg_altered
104+ + character_arg_altered
123105 + ".json' file." )
124106 . green( )
125107 ) ;
126108
109+ // デフォルト画像URL設定
110+ let mut embed_image = IMAGE_DEFAULT . to_string ( ) ;
111+
127112 // 画像リンクの探索 対象技の画像リンクを検索
128113 for img_links in image_links {
129114 // 対象技の入力と画像情報の入力が一致し、画像リンクが存在する場合
@@ -133,22 +118,38 @@ pub async fn advanced(
133118 }
134119 }
135120
121+ Ok ( ( move_info, embed_image) )
122+ }
123+
124+ /// 技情報の詳細な埋め込みメッセージを作成する関数
125+ ///
126+ /// # 引数
127+ /// * `move_info` - 技情報
128+ /// * `embed_image` - 埋め込む画像のURL
129+ /// * `character_arg_altered` - 正式なキャラクター名
130+ ///
131+ /// # 戻り値
132+ /// 埋め込みメッセージのベクター
133+ fn create_advanced_embeds (
134+ move_info : & MoveInfo ,
135+ embed_image : & str ,
136+ character_arg_altered : & str ,
137+ ) -> Vec < CreateEmbed > {
136138 // 埋め込みメッセージ群生成用ベクターの初期化
137139 let mut vec_embeds = Vec :: new ( ) ;
138140 // 埋め込みタイトルの作成 キャラクター名と技名を組み合わせたタイトル
139141 let embed_title = "__**" . to_owned ( ) + & move_info. input + "**__" ;
140142 // 埋め込みURLの作成 Dustloop Wiki のキャラクター概要ページURL生成
141- let embed_url =
142- "https://dustloop.com/w/GGST/" . to_owned ( ) + & character_arg_altered + "#Overview" ;
143+ let embed_url = "https://dustloop.com/w/GGST/" . to_owned ( ) + character_arg_altered + "#Overview" ;
143144 // 埋め込みフッターの作成 技に関するキャプションを利用
144145 let embed_footer = CreateEmbedFooter :: new ( & move_info. caption ) ;
145146
146147 // 埋め込みメッセージの生成 技データの各パラメータをフィールドとして追加
147148 let embed = CreateEmbed :: new ( )
148149 . color ( EMBED_COLOR ) // 埋め込みカラー設定
149- . title ( & embed_title) // タイトル設定
150- . url ( & embed_url) // URL設定
151- . image ( & embed_image) // 画像リンク設定
150+ . title ( embed_title) // タイトル設定
151+ . url ( embed_url) // URL設定
152+ . image ( embed_image) // 画像リンク設定
152153 . fields ( vec ! [
153154 (
154155 "ダメージ" ,
@@ -235,6 +236,67 @@ pub async fn advanced(
235236 vec_embeds. push ( embed2) ; // ベクターに追加
236237 }
237238
239+ vec_embeds
240+ }
241+
242+ /// 技の詳細情報を埋め込みメッセージで表示するコマンド
243+ ///
244+ /// # 引数
245+ /// * `ctx` - コマンドコンテキスト
246+ /// * `character` - キャラクター名または愛称
247+ /// * `character_move` - 技名、入力、またはエイリアス
248+ ///
249+ /// # 戻り値
250+ /// 処理結果 `Result<(), AppError>`
251+ #[ poise:: command( prefix_command, slash_command) ]
252+ pub async fn advanced (
253+ ctx : Context < ' _ > ,
254+ #[ min_length = 2 ]
255+ #[ description = "キャラクター名または愛称" ]
256+ character : String ,
257+ #[ min_length = 2 ]
258+ #[ rename = "move" ]
259+ #[ description = "技名、入力、またはエイリアス" ]
260+ character_move : String ,
261+ ) -> Result < ( ) , AppError > {
262+ // コマンド引数の表示 引数確認用
263+ println ! (
264+ "{}" ,
265+ ( "Command Args: '" . to_owned( ) + & character + ", " + & character_move + "'" ) . purple( )
266+ ) ;
267+
268+ // 入力チェックの実施 各種前提条件チェック
269+ if ( check:: adaptive_check (
270+ ctx,
271+ check:: CheckOptions {
272+ data_folder : true ,
273+ nicknames_json : true ,
274+ character_folders : true ,
275+ character_jsons : true ,
276+ character_images : true ,
277+ } ,
278+ )
279+ . await )
280+ . is_err ( )
281+ {
282+ return Ok ( ( ) ) ;
283+ }
284+
285+ // キャラクターデータ読み込み
286+ let Ok ( character_arg_altered) = load_character_data ( & character, & ctx) . await else {
287+ return Ok ( ( ) ) ;
288+ } ;
289+
290+ // 技情報と画像データ読み込み
291+ let Ok ( ( move_info, embed_image) ) =
292+ find_move_and_images ( & character_arg_altered, & character_move, & ctx) . await
293+ else {
294+ return Ok ( ( ) ) ;
295+ } ;
296+
297+ // 埋め込みメッセージ作成
298+ let vec_embeds = create_advanced_embeds ( & move_info, & embed_image, & character_arg_altered) ;
299+
238300 // 返信メッセージ用オブジェクト生成 送信用オブジェクトの初期化
239301 let mut reply = poise:: CreateReply :: default ( ) ;
240302 // 生成した埋め込みメッセージ群を返信オブジェクトに追加
0 commit comments