diff --git a/frontend/apps/crates/entry/asset/play/src/jig/dom.rs b/frontend/apps/crates/entry/asset/play/src/jig/dom.rs index 89b98492a..007c73253 100644 --- a/frontend/apps/crates/entry/asset/play/src/jig/dom.rs +++ b/frontend/apps/crates/entry/asset/play/src/jig/dom.rs @@ -464,8 +464,6 @@ impl JigPlayer { map_ref! { let active_module = self.active_module.signal(), let jig = self.jig.signal_cloned() => move { - log::info!("active_module_has_scoring: {:?}", active_module); - log::info!("active_module_has_scoring: {:?}", jig.as_ref().map(|jig| jig.jig_data.modules.clone())); match (active_module, jig) { (Some(active_module), Some(jig)) if jig.jig_data.modules[*active_module].kind.has_scoring() => true, _ => false, diff --git a/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/actions.rs b/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/actions.rs index 9eff70573..817d8cc08 100644 --- a/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/actions.rs +++ b/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/actions.rs @@ -88,10 +88,7 @@ impl CodeSessions { .modules .into_iter() .map(|module| { - let stable_module_id = match &module { - JigPlaySessionModule::Matching(module) => module.stable_module_id, - JigPlaySessionModule::CardQuiz(module) => module.stable_module_id, - }; + let stable_module_id = module.stable_module_id(); (stable_module_id, module) }) .collect::>(); diff --git a/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/dom.rs b/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/dom.rs index 2d1d3e25e..3b0d4a6da 100644 --- a/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/dom.rs +++ b/frontend/apps/crates/entry/classroom/src/codes/jig_code_sessions/dom.rs @@ -218,10 +218,7 @@ impl CodeSessions { _ => false, }; let sessions = session.info.unwrap().modules.into_iter().map(|module| { - let stable_module_id = match &module { - JigPlaySessionModule::Matching(module) => module.stable_module_id, - JigPlaySessionModule::CardQuiz(module) => module.stable_module_id, - }; + let stable_module_id = module.stable_module_id(); (stable_module_id, module) }).collect::>(); html!("div", { diff --git a/frontend/apps/crates/entry/module/drag-drop/play/src/base/game/playing/actions.rs b/frontend/apps/crates/entry/module/drag-drop/play/src/base/game/playing/actions.rs index ab18f7b6f..7cfe6aa51 100644 --- a/frontend/apps/crates/entry/module/drag-drop/play/src/base/game/playing/actions.rs +++ b/frontend/apps/crates/entry/module/drag-drop/play/src/base/game/playing/actions.rs @@ -1,8 +1,11 @@ +use std::iter::repeat_with; use std::rc::Rc; use super::state::*; use components::module::_common::play::prelude::{BaseExt, ModuleEnding, ModulePlayPhase}; +use shared::domain::jig::codes::{JigPlaySessionDragDropRound, JigPlaySessionModule}; use shared::domain::module::body::_groups::design::Trace; +use utils::toasts; use utils::{drag::Drag, prelude::*, resize::get_resize_info}; use crate::debug::*; @@ -34,6 +37,11 @@ impl PlayState { *item.target_index.borrow_mut() = Some(index); } } + + self.game.base.play_report.lock_mut().items = + repeat_with(|| JigPlaySessionDragDropRound { failed_tries: 0 }) + .take(traces.len()) + .collect(); } pub fn evaluate_all_completed(state: Rc) -> bool { @@ -104,6 +112,15 @@ impl PlayState { // Move the item back to it's origin item.move_back_to_origin(); item.play_audio_effect(AudioEffect::Wrong); + state + .game + .base + .play_report + .lock_mut() + .items + .get_mut(item_index) + .unwrap_ji() + .failed_tries += 1; } Some((target_transform, index)) => { // If the number of items that can be placed in a trace is just 1, then we snap @@ -126,6 +143,21 @@ impl PlayState { } item.completed.set_neq(true); + + let points = calculate_point_count( + state + .game + .base + .play_report + .lock_mut() + .items + .get(item_index) + .unwrap_ji() + .failed_tries as u32, + ); + let _ = IframeAction::new(ModuleToJigPlayerMessage::AddPoints(points)) + .try_post_message_to_player(); + if !Self::evaluate_all_completed(state.clone()) { item.play_audio_effect(AudioEffect::Correct); } else { @@ -133,6 +165,16 @@ impl PlayState { AUDIO_MIXER.with(|mixer| { let positive_audio: AudioPath<'_> = mixer.get_random_positive().into(); mixer.play_oneshot_on_ended(positive_audio, move || { + let info = state.game.base.play_report.lock_ref().clone(); + let info = JigPlaySessionModule::DragDrop(info); + let msg = IframeAction::new( + ModuleToJigPlayerMessage::AddCodeSessionInfo(info), + ); + if msg.try_post_message_to_player().is_err() { + toasts::error("Error saving progress"); + log::info!("Error saving progress"); + } + // Once the positive feedback effect has played, we can show/play the // feedback for the activity. If we played this at the same time, it // we could have two audio clips playing simultaneously which would be @@ -154,6 +196,12 @@ impl PlayState { } } +fn calculate_point_count(tried_count: u32) -> u32 { + // start with 2 point, reduce one point for every try. min points: 0. + let base = 2_u32; + base.saturating_sub(tried_count) +} + pub enum AudioEffect { /// Drop sound Correct, diff --git a/frontend/apps/crates/entry/module/drag-drop/play/src/base/state.rs b/frontend/apps/crates/entry/module/drag-drop/play/src/base/state.rs index 042263769..0f0fb2c89 100644 --- a/frontend/apps/crates/entry/module/drag-drop/play/src/base/state.rs +++ b/frontend/apps/crates/entry/module/drag-drop/play/src/base/state.rs @@ -1,7 +1,10 @@ use components::module::_common::play::prelude::*; use shared::domain::{ asset::{Asset, AssetId}, - jig::player::{ModuleConfig, Seconds}, + jig::{ + codes::JigPlaySessionDragDrop, + player::{ModuleConfig, Seconds}, + }, module::{ body::{ ModuleAssist, @@ -34,6 +37,7 @@ pub struct Base { pub item_targets: Vec, pub target_areas: Vec, pub module_phase: Mutable, + pub play_report: Mutable, } impl Base { @@ -65,6 +69,7 @@ impl Base { item_targets: content.item_targets, target_areas: content.target_areas, module_phase: init_args.play_phase, + play_report: Mutable::new(JigPlaySessionDragDrop::new(stable_module_id)), }) } } diff --git a/shared/rust/src/domain/jig/codes.rs b/shared/rust/src/domain/jig/codes.rs index d3eb34b60..798b80f48 100644 --- a/shared/rust/src/domain/jig/codes.rs +++ b/shared/rust/src/domain/jig/codes.rs @@ -138,6 +138,19 @@ pub enum JigPlaySessionModule { Matching(JigPlaySessionMatching), /// Card quiz CardQuiz(JigPlaySessionCardQuiz), + /// Drag and drop + DragDrop(JigPlaySessionDragDrop), +} + +impl JigPlaySessionModule { + /// get stable module id + pub fn stable_module_id(&self) -> StableModuleId { + match self { + Self::Matching(module) => module.stable_module_id, + Self::CardQuiz(module) => module.stable_module_id, + Self::DragDrop(module) => module.stable_module_id, + } + } } impl JigPlaySessionModuleGetPointsEarned for JigPlaySessionModule { @@ -145,6 +158,7 @@ impl JigPlaySessionModuleGetPointsEarned for JigPlaySessionModule { match self { JigPlaySessionModule::Matching(module) => module.get_points_earned(), JigPlaySessionModule::CardQuiz(module) => module.get_points_earned(), + JigPlaySessionModule::DragDrop(module) => module.get_points_earned(), } } } @@ -267,6 +281,49 @@ pub struct JigPlaySessionCardQuizRound { pub failed_tries: u16, } +/// Drag and drop module +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct JigPlaySessionDragDrop { + /// related module id + pub stable_module_id: StableModuleId, + + /// list of rounds for this module + pub items: Vec, +} + +impl JigPlaySessionDragDrop { + /// create new from module id + pub fn new(stable_module_id: StableModuleId) -> Self { + Self { + stable_module_id, + items: Vec::new(), + } + } +} + +impl JigPlaySessionModuleGetPointsEarned for JigPlaySessionDragDrop { + fn get_points_earned(&self) -> PointsEarned { + let mut available = 0; + let mut earned = 0; + for card in &self.items { + available += 2; + earned += match card.failed_tries { + 0 => 2, + 1 => 1, + _ => 0, + }; + } + PointsEarned { available, earned } + } +} + +/// +#[derive(Clone, Debug, Hash, Serialize, Deserialize)] +pub struct JigPlaySessionDragDropRound { + /// unsuccessful try count + pub failed_tries: u16, +} + /// Types for Jig session instance endpoints pub mod instance { use macros::make_path_parts; diff --git a/shared/rust/src/domain/module.rs b/shared/rust/src/domain/module.rs index b63ef0ef5..89df325cd 100644 --- a/shared/rust/src/domain/module.rs +++ b/shared/rust/src/domain/module.rs @@ -132,7 +132,7 @@ impl ModuleKind { /// Whether this ModuleKind has scoring pub fn has_scoring(&self) -> bool { match self { - Self::Matching | Self::CardQuiz => true, + Self::Matching | Self::CardQuiz | Self::DragDrop => true, _ => false, } }