Two teams try and fill in any horizontal, vertical, or diagonal line on a bingo board by playing maps on osu!
osu.bingo
osu
1use chrono::{DateTime, Utc};
2use juniper::{FieldError, FieldResult, graphql_object};
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 database::DataContext,
7 schema::{BingoSquare, Float, GameUser, Long},
8};
9
10#[derive(sqlx::FromRow, Serialize, Deserialize)]
11pub struct Score {
12 id: String,
13
14 score_id: i64,
15 user_id: i32,
16
17 date: DateTime<Utc>,
18 mods: Option<String>,
19 lazer: bool,
20
21 percentage: Option<f32>,
22 is_fc: bool,
23 score: i32,
24 pp: Option<f32>,
25 grade: String,
26 accuracy: f32,
27 max_combo: i32,
28
29 important: bool,
30 claim: ClaimAction,
31
32 square_id: String,
33 game_user_id: String,
34}
35
36#[derive(sqlx::Type, Deserialize, Serialize, juniper::GraphQLEnum)]
37#[sqlx(type_name = "claim_action", rename_all = "PascalCase")]
38#[serde(rename_all = "PascalCase")]
39pub enum ClaimAction {
40 NoChange,
41 Claim,
42 ReClaim,
43 Win,
44}
45
46#[graphql_object(description = "A user's score on a certain bingo square", Context = DataContext)]
47impl Score {
48 pub fn id(&self) -> &str {
49 &self.id
50 }
51
52 /// https://osu.ppy.sh/s/[score_id]
53 pub fn score_id(&self) -> Long {
54 self.score_id.into()
55 }
56
57 /// The osu! id of the user that played the map
58 pub fn user_id(&self) -> i32 {
59 self.user_id
60 }
61
62 /// When the score was set
63 pub fn date(&self) -> &DateTime<Utc> {
64 &self.date
65 }
66
67 /// The mods the user used when playing
68 pub fn mods(&self) -> Option<&String> {
69 self.mods.as_ref()
70 }
71
72 /// Whether or not the user submitted the score on lazer
73 pub fn is_lazer(&self) -> bool {
74 self.lazer
75 }
76
77 /// If you fail, how far through the map you got
78 pub fn percentage(&self) -> Option<Float> {
79 self.percentage.map(|f| f.into())
80 }
81
82 /// Whether or not the user fulll comboed the map
83 pub fn is_fc(&self) -> bool {
84 self.is_fc
85 }
86
87 /// The numerical (standardized) score on the map
88 pub fn score(&self) -> i32 {
89 self.score
90 }
91
92 /// The amount of pp recieved (null if not ranked)
93 pub fn pp(&self) -> Option<Float> {
94 self.pp.map(|f| f.into())
95 }
96
97 /// The letter grade they got on the map
98 pub fn grade(&self) -> &str {
99 &self.grade
100 }
101
102 /// The final accuracy they got on the map
103 pub fn accuracy(&self) -> Float {
104 self.accuracy.into()
105 }
106
107 /// The maximum combo achieved on the map
108 pub fn max_combo(&self) -> i32 {
109 self.max_combo
110 }
111
112 /// Whether or not the score would the conditions to claim the square
113 pub fn claimworthy(&self) -> bool {
114 self.important
115 }
116
117 /// The affect this score had on the result of the game's board
118 pub fn claim(&self) -> &ClaimAction {
119 &self.claim
120 }
121
122 /// The game user that set this score
123 pub async fn gameuser(&self, context: &DataContext) -> FieldResult<GameUser> {
124 context
125 .acquire()
126 .await
127 .get_gameuser_by_id(&self.game_user_id)
128 .await
129 .map_err(FieldError::from)
130 }
131
132 /// The square this score was a part of
133 pub async fn square(&self, context: &DataContext) -> FieldResult<BingoSquare> {
134 context
135 .acquire()
136 .await
137 .get_square_by_id(&self.square_id)
138 .await
139 .map_err(FieldError::from)
140 }
141}