diff --git a/client/src/game/container.js b/client/src/game/container.js index 501640467..d55acc176 100644 --- a/client/src/game/container.js +++ b/client/src/game/container.js @@ -2,6 +2,7 @@ import * as PIXI from 'pixi.js-legacy' import { Viewport } from 'pixi-viewport' import Map from './map' import gameHelper from '../services/gameHelper' +import LearningHelper from '../services/learningHelper' import textureService from './texture' class GameContainer { @@ -134,10 +135,12 @@ class GameContainer { zoomIn () { this.viewport.zoomPercent(0.5, true) + LearningHelper.conceptUsed(LearningHelper.concept.CAMERA_ZOOM) } zoomOut () { this.viewport.zoomPercent(-0.3, true) + LearningHelper.conceptUsed(LearningHelper.concept.CAMERA_ZOOM) } setupViewport (game) { @@ -176,6 +179,7 @@ class GameContainer { maxHeight, }) + this.viewport.on('drag-end', this.onViewportDragged.bind(this)) this.viewport.on('zoomed-end', this.onViewportZoomed.bind(this)) this.viewport.on('pointerdown', this.map.onViewportPointerDown.bind(this.map)) } @@ -263,10 +267,15 @@ class GameContainer { this.map.onTick(deltaTime) } + onViewportDragged (e) { + LearningHelper.conceptUsed(LearningHelper.concept.CAMERA_PAN) + } + onViewportZoomed (e) { let zoomPercent = this.getViewportZoomPercentage() this.map.refreshZoom(zoomPercent) + LearningHelper.conceptUsed(LearningHelper.concept.CAMERA_ZOOM) } setMode (mode, args) { diff --git a/client/src/game/map.js b/client/src/game/map.js index e841681cd..82e89f96b 100644 --- a/client/src/game/map.js +++ b/client/src/game/map.js @@ -8,6 +8,7 @@ import Territories from './territories' import PlayerNames from './playerNames' import EventEmitter from 'events' import gameHelper from '../services/gameHelper' +import LearningHelper from '../services/learningHelper' import AnimationService from './animation' import PathManager from './PathManager' import OrbitalLocationLayer from './orbital' @@ -605,6 +606,7 @@ class Map extends EventEmitter { } this.panToPlayer(game, player) + LearningHelper.conceptUsed(LearningHelper.concept.CAMERA_PAN) } panToStar (star) { diff --git a/client/src/services/data/concepts.js b/client/src/services/data/concepts.js new file mode 100644 index 000000000..ce86076fd --- /dev/null +++ b/client/src/services/data/concepts.js @@ -0,0 +1,78 @@ +import GameHelper from '../gameHelper' +import LearningHelper from '../learningHelper' +import MENU_STATES from './menuStates' + +export default [ + { + id: LearningHelper.concept.CAMERA_PAN, + title: "Camera pan", + text: "Move across the map by clicking and dragging with any MOUSE BUTTON.\nPress the h or space keyboard shortcut to return to your Home star.", + priority: 10, + onConceptUsed: function (self) { + this.markProgress(self, 30) + } + }, + { + id: LearningHelper.concept.CAMERA_ZOOM, + title: "Camera zoom", + text: "Zoom in and out with the MOUSE WHEEL or + and - keys.", + priority: 10, + onConceptUsed: function (self) { + this.markProgress(self, 20) + } + }, + { + id: LearningHelper.concept.CARRIERS, + title: "Carriers", + text: "Carriers are used to transport Ships through hyperspace to reach other Stars. They can only be built at Stars and must hold a minimum of 1 Ship.\nCarriers are displayed as small ship icons with a circular coloured halo, much like stars. The number of ships that a carrier has will be displayed when zoomed in.\nClick on the carrier to view it in detail.", + priority: 20, + pre: [LearningHelper.concept.CAMERA_ZOOM], + onMenuRequested: function (self, menuState) { + if (menuState.state === MENU_STATES.CARRIER_DETAIL) { + this.markLearned(self) + } + } + }, + { + id: LearningHelper.concept.CAPITAL_STAR, + title: "Capital Star", + text: "The Capital Star is your home world. You can recognize as it has 9 points.\nSelect your Capital Star and view its details.", + priority: 20, + pre: [LearningHelper.concept.CAMERA_ZOOM], + onMenuRequested: function (self, menuState) { + if (menuState.state === MENU_STATES.STAR_DETAIL) { + const starId = menuState.args + const star = GameHelper.getStarById(this.$store.state.game, starId) + if (star.homeStar) { + this.markLearned(self) + } + } + } + }, + { + id: LearningHelper.concept.BULK_UPGRADE, + title: "Bulk Upgrade", + text: "Improve your infrastructure by spending your budget on the cheapest expansions first.\nAccess Bulk Upgrade from the menu / sidebar or using the b keyboard shortcut.", + priority: 100, + pre: [], + isAvailable: function (self) { + return this.isGameInProgress + }, + onConceptUsed: function (self) { + this.markLearned(self) + } + }, + { + id: LearningHelper.concept.COMBAT_CALCULATOR, + title: "Combat Calculator", + text: "Use this handy tool to predict the outcome of combat based on the weapon levels and numbers of the Attacker and Defender.\nAccess the Combat Calculator from the menu / sidebar, using the c keyboard shortcut or from the Carrier detail window.", + priority: 100, + pre: [LearningHelper.concept.CARRIERS], + isAvailable: function (self) { + return this.isGameInProgress + }, + onConceptUsed: function (self) { + this.markLearned(self) + } + }, +] diff --git a/client/src/services/learningHelper.js b/client/src/services/learningHelper.js new file mode 100644 index 000000000..ec747042e --- /dev/null +++ b/client/src/services/learningHelper.js @@ -0,0 +1,20 @@ +import eventBus from '../eventBus' + +const CONCEPT_IDS = { + BULK_UPGRADE: 'bulk-upgrade', + CAMERA_PAN: 'camera-pan', + CAMERA_ZOOM: 'camera-zoom', + CAPITAL_STAR: 'capital-star', + CARRIERS: 'carriers', + COMBAT_CALCULATOR: 'combat-calculator', +} + +class LearningHelper { + concept = CONCEPT_IDS + + conceptUsed(conceptId) { + eventBus.$emit('onConceptUsed', conceptId) + } +} + +export default new LearningHelper() diff --git a/client/src/store.js b/client/src/store.js index 9fa671708..2f73fdbdb 100644 --- a/client/src/store.js +++ b/client/src/store.js @@ -24,7 +24,8 @@ export default new Vuex.Store({ starSpecialists: null, carrierSpecialists: null, settings: null, - confirmationDialog: {} + confirmationDialog: {}, + learnedConcepts: null }, mutations: { // Menu @@ -143,6 +144,15 @@ export default new Vuex.Store({ state.confirmationDialog = settings }, + setLearnedConcept (state, conceptId) { + if (!state.learnedConcepts) + state.learnedConcepts = {} + state.learnedConcepts[conceptId] = true + }, + clearLearnedConcepts (state) { + state.learnedConcepts = null + }, + setUnreadMessages (state, count) { state.unreadMessages = count }, diff --git a/client/src/views/game/Game.vue b/client/src/views/game/Game.vue index d4a460cdc..9d9da0f64 100644 --- a/client/src/views/game/Game.vue +++ b/client/src/views/game/Game.vue @@ -16,6 +16,7 @@ + @@ -28,6 +29,7 @@ import GameContainer from './components/GameContainer.vue' import MENU_STATES from '../../services/data/menuStates' import MainBar from './components/menu/MainBar.vue' import Chat from './components/inbox/Chat.vue' +import AdaptiveTutor from './components/tutor/AdaptiveTutor.vue' import GameApiService from '../../services/api/game' import UserApiService from '../../services/api/user' import GameHelper from '../../services/gameHelper' @@ -42,7 +44,8 @@ export default { 'loading-spinner': LoadingSpinnerVue, 'game-container': GameContainer, 'main-bar': MainBar, - 'chat': Chat + 'adaptive-tutor': AdaptiveTutor, + 'chat': Chat, }, data () { return { diff --git a/client/src/views/game/components/carrier/CombatCalculator.vue b/client/src/views/game/components/carrier/CombatCalculator.vue index 348d2dd53..732ff1ac0 100644 --- a/client/src/views/game/components/carrier/CombatCalculator.vue +++ b/client/src/views/game/components/carrier/CombatCalculator.vue @@ -100,6 +100,7 @@ import LoadingSpinnerVue from '../../../components/LoadingSpinner' import MenuTitle from '../MenuTitle' import FormErrorList from '../../../components/FormErrorList' import GameHelper from '../../../../services/gameHelper' +import LearningHelper from '../../../../services/learningHelper' import CarrierApiService from '../../../../services/api/carrier' import GameContainer from '../../../../game/container' @@ -232,6 +233,7 @@ export default { console.error(err) } + LearningHelper.conceptUsed(LearningHelper.concept.COMBAT_CALCULATOR) this.isLoading = false } } diff --git a/client/src/views/game/components/star/BulkInfrastructureUpgrade.vue b/client/src/views/game/components/star/BulkInfrastructureUpgrade.vue index d7389558f..c8ec225d1 100644 --- a/client/src/views/game/components/star/BulkInfrastructureUpgrade.vue +++ b/client/src/views/game/components/star/BulkInfrastructureUpgrade.vue @@ -119,6 +119,7 @@ import MenuTitle from '../MenuTitle' import FormErrorList from '../../../components/FormErrorList' import starService from '../../../../services/api/star' import GameHelper from '../../../../services/gameHelper' +import LearningHelper from '../../../../services/learningHelper' import AudioService from '../../../../game/audio' import GameContainer from '../../../../game/container' import BulkInfrastructureUpgradeStarTableVue from './BulkInfrastructureUpgradeStarTable' @@ -275,6 +276,7 @@ export default { this.errors = err.response.data.errors || [] } + LearningHelper.conceptUsed(LearningHelper.concept.BULK_UPGRADE) this.hasChecked = false this.isUpgrading = false }, diff --git a/client/src/views/game/components/tutor/AdaptiveTutor.vue b/client/src/views/game/components/tutor/AdaptiveTutor.vue new file mode 100644 index 000000000..d57d585f1 --- /dev/null +++ b/client/src/views/game/components/tutor/AdaptiveTutor.vue @@ -0,0 +1,283 @@ + + + + + diff --git a/client/src/views/game/components/tutor/ConceptDetail.vue b/client/src/views/game/components/tutor/ConceptDetail.vue new file mode 100644 index 000000000..238b6437b --- /dev/null +++ b/client/src/views/game/components/tutor/ConceptDetail.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/client/src/views/game/components/tutor/ConceptList.vue b/client/src/views/game/components/tutor/ConceptList.vue new file mode 100644 index 000000000..3d12749b1 --- /dev/null +++ b/client/src/views/game/components/tutor/ConceptList.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/client/src/views/game/components/tutor/ConceptListItem.vue b/client/src/views/game/components/tutor/ConceptListItem.vue new file mode 100644 index 000000000..7abf883ac --- /dev/null +++ b/client/src/views/game/components/tutor/ConceptListItem.vue @@ -0,0 +1,71 @@ + + + + +