mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-28 18:15:52 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
72336bd8c7
18 changed files with 466 additions and 187 deletions
|
@ -68,6 +68,8 @@ class AudioPlayer extends CocoClass
|
|||
return null unless say = soundTriggers?.say
|
||||
message = _.string.slugify message
|
||||
return sound if sound = say[message]
|
||||
if _.string.startsWith message, 'attack'
|
||||
return sound if sound = say.attack
|
||||
defaults = say.defaultSimlish
|
||||
if say.swearingSimlish?.length and _.find(swears, (s) -> message.search(s) isnt -1)
|
||||
defaults = say.swearingSimlish
|
||||
|
|
|
@ -99,9 +99,9 @@ module.exports = class World
|
|||
continueLaterFn = =>
|
||||
@loadFrames(loadedCallback, errorCallback, loadProgressCallback, preloadedCallback, skipDeferredLoading, loadUntilFrame) unless @destroyed
|
||||
if @realTime and not @countdownFinished
|
||||
if @levelID in ['the-first-kithmaze', 'descending-further', 'the-second-kithmaze', 'the-final-kithmaze', 'the-gauntlet', 'winding-trail', 'thornbush-farm']
|
||||
if @levelID in ['the-first-kithmaze', 'the-second-kithmaze', 'the-final-kithmaze', 'the-gauntlet', 'winding-trail', 'thornbush-farm']
|
||||
@realTimeSpeedFactor = 5
|
||||
else if @levelID in ['forgotten-gemsmith', 'tactical-strike', 'kithgard-gates']
|
||||
else if @levelID in ['forgotten-gemsmith', 'descending-further', 'tactical-strike', 'kithgard-gates']
|
||||
@realTimeSpeedFactor = 3
|
||||
else
|
||||
@realTimeSpeedFactor = 1
|
||||
|
|
|
@ -268,7 +268,7 @@ _.extend LevelSessionSchema.properties,
|
|||
description: 'The opponent\'s ranking in a given match'
|
||||
type: 'number'
|
||||
codeLanguage:
|
||||
type: 'string'
|
||||
type: ['string', 'null'] # 'null' in case an opponent session got corrupted, don't care much here
|
||||
description: 'What submittedCodeLanguage the opponent used during the match'
|
||||
|
||||
c.extendBasicProperties LevelSessionSchema, 'level.session'
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
c = require 'schemas/schemas'
|
||||
|
||||
module.exports =
|
||||
'real-time-multiplayer:joined-game': c.object {title: 'Multiplayer joined game', required: ['session']},
|
||||
'real-time-multiplayer:created-game': c.object {title: 'Multiplayer created game', required: ['session']},
|
||||
session: {type: 'object'}
|
||||
|
||||
'real-time-multiplayer:left-game': c.object {title: 'Multiplayer left game'}
|
||||
'real-time-multiplayer:joined-game': c.object {title: 'Multiplayer joined game', required: ['id', 'session']},
|
||||
id: {type: 'string'}
|
||||
session: {type: 'object'}
|
||||
|
||||
'real-time-multiplayer:left-game': c.object {title: 'Multiplayer left game', required: ['id']},
|
||||
id: {type: 'string'}
|
||||
|
||||
'real-time-multiplayer:manual-cast': c.object {title: 'Multiplayer manual cast'}
|
||||
|
||||
|
@ -12,3 +17,6 @@ module.exports =
|
|||
code: {type: 'object'}
|
||||
codeLanguage: {type: 'string'}
|
||||
team: {type: 'string'}
|
||||
|
||||
'real-time-multiplayer:player-status': c.object {title: 'Multiplayer player status', required: ['status']},
|
||||
status: {type: 'string'}
|
||||
|
|
14
app/styles/play/level/multiplayer-status.sass
Normal file
14
app/styles/play/level/multiplayer-status.sass
Normal file
|
@ -0,0 +1,14 @@
|
|||
@import "app/styles/mixins"
|
||||
@import "app/styles/bootstrap/variables"
|
||||
|
||||
// TODO: Replace this devart with nice shinies
|
||||
|
||||
#multiplayer-status-view
|
||||
.player-count
|
||||
color: white
|
||||
.players-available
|
||||
color: lightblue
|
||||
.players-unavailable
|
||||
color: fuchsia
|
||||
.game-status
|
||||
color: lightgreen
|
|
@ -16,7 +16,7 @@ block modal-body-content
|
|||
- submenus.splice(0, 1);
|
||||
ul.nav.nav-tabs#game-menu-nav
|
||||
for submenu, index in submenus
|
||||
li(class=index ? "" : "active")
|
||||
li(class=submenu === showTab || index === 0 && !showTab ? "active" : "")
|
||||
a(href='#' + submenu + '-view', data-toggle='tab')
|
||||
h2(data-i18n='game_menu.' + submenu.replace('-', '_') + '_tab')
|
||||
em(data-i18n='game_menu.' + submenu.replace('-', '_') + '_caption')
|
||||
|
|
|
@ -29,22 +29,24 @@ if ladderGame
|
|||
|
||||
div#created-multiplayer-session
|
||||
h3 Your Game
|
||||
if currentMultiplayerSession
|
||||
if currentRealTimeSession
|
||||
div
|
||||
span(style="margin:10px")= currentMultiplayerSession.get('levelID')
|
||||
span(style="margin:10px")= currentMultiplayerSession.get('creatorName')
|
||||
span(style="margin:10px")= currentMultiplayerSession.get('state')
|
||||
span(style="margin:10px")= currentMultiplayerSession.id
|
||||
span(style="margin:10px")= currentRealTimeSession.get('levelID')
|
||||
span(style="margin:10px")= currentRealTimeSession.get('creatorName')
|
||||
span(style="margin:10px")= currentRealTimeSession.get('state')
|
||||
span(style="margin:10px")= currentRealTimeSession.id
|
||||
button#leave-game-button(data-item=item) Leave Game
|
||||
div
|
||||
- var players = playersCollections[currentMultiplayerSession.id]
|
||||
span(style="margin:10px") Players:
|
||||
- for (var i=0; i < players.length; i++) {
|
||||
- var name = players.at(i).get('name')
|
||||
- var team = players.at(i).get('team')
|
||||
span(style="margin:10px")= name
|
||||
span(style="margin:10px")= team
|
||||
- }
|
||||
- var players = realTimeSessionPlayers[currentRealTimeSession.id]
|
||||
if players
|
||||
span(style="margin:10px") Players:
|
||||
- for (var i=0; i < players.length; i++) {
|
||||
span(style="margin:10px")= players.at(i).get('name')
|
||||
span(style="margin:10px")= players.at(i).get('team')
|
||||
span(style="margin:10px")= players.at(i).get('state')
|
||||
- }
|
||||
else
|
||||
span No Players?
|
||||
else
|
||||
div Click something above to create a game.
|
||||
|
||||
|
@ -52,33 +54,31 @@ if ladderGame
|
|||
|
||||
div#open-games
|
||||
h3 Open Games
|
||||
// TODO: do not let you join ones with same-team opponent
|
||||
//- TODO: do not let you join ones with same-team opponent
|
||||
- var noOpenGames = true
|
||||
if multiplayerSessions
|
||||
- for (var i=0; i < multiplayerSessions.length; i++) {
|
||||
if levelID === multiplayerSessions[i].get('levelID') && multiplayerSessions[i].get('state') === 'creating'
|
||||
- var id = multiplayerSessions[i].get('id')
|
||||
- var players = playersCollections[id]
|
||||
if players && players.length < 2
|
||||
- noOpenGames = false
|
||||
- var creatorName = multiplayerSessions[i].get('creatorName')
|
||||
- var creator = multiplayerSessions[i].get('creator')
|
||||
- var state = multiplayerSessions[i].get('state')
|
||||
- var item = multiplayerSessions[i]
|
||||
div
|
||||
button#join-game-button(data-item=item) Join Game
|
||||
span(style="margin:10px")= levelID
|
||||
span(style="margin:10px")= creatorName
|
||||
span(style="margin:10px")= state
|
||||
span(style="margin:10px")= id
|
||||
div
|
||||
span(style="margin:10px") Players:
|
||||
- for (var j=0; j < players.length; j++) {
|
||||
- var name = players.at(j).get('name')
|
||||
- var team = players.at(j).get('team')
|
||||
span(style="margin:10px")= name
|
||||
span(style="margin:10px")= team
|
||||
- }
|
||||
- for (var i=0; i < realTimeSessions.length; i++) {
|
||||
if (currentRealTimeSession && realTimeSessions.at(i).id == currentRealTimeSession.id)
|
||||
- continue
|
||||
if levelID === realTimeSessions.at(i).get('levelID') && realTimeSessions.at(i).get('state') === 'creating'
|
||||
- var id = realTimeSessions.at(i).get('id')
|
||||
- var players = realTimeSessionPlayers[id]
|
||||
if players && players.length === 1
|
||||
- noOpenGames = false
|
||||
- var creatorName = realTimeSessions.at(i).get('creatorName')
|
||||
- var creator = realTimeSessions.at(i).get('creator')
|
||||
- var state = realTimeSessions.at(i).get('state')
|
||||
- var item = realTimeSessions.at(i)
|
||||
div
|
||||
button#join-game-button(data-item=item) Join Game
|
||||
span(style="margin:10px")= levelID
|
||||
span(style="margin:10px")= creatorName
|
||||
span(style="margin:10px")= state
|
||||
span(style="margin:10px")= id
|
||||
div
|
||||
span(style="margin:10px") Players:
|
||||
span(style="margin:10px")= players.at(0).get('name')
|
||||
span(style="margin:10px")= players.at(0).get('team')
|
||||
span(style="margin:10px")= players.at(0).get('state')
|
||||
- }
|
||||
if noOpenGames
|
||||
div No games available.
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#level-chat-view
|
||||
|
||||
#multiplayer-status-view
|
||||
|
||||
#playback-view
|
||||
|
||||
#thang-hud
|
||||
|
|
|
@ -8,16 +8,6 @@ h4.title
|
|||
| #{worldName}
|
||||
span.spl.spr.editor-dash -
|
||||
a(href=editorLink, data-i18n="nav.editor", title="Open " + worldName + " in the Level Editor") Editor
|
||||
if multiplayerSession
|
||||
- found = false
|
||||
- for (var i=0; i < multiplayerPlayers.length; i++) {
|
||||
if (multiplayerPlayers.at(i).id !== meID)
|
||||
span.spl.spr - vs #{multiplayerPlayers.at(i).get('name')}
|
||||
- found = true
|
||||
- break
|
||||
- }
|
||||
if !found
|
||||
span.spl.spr - waiting...
|
||||
|
||||
button.btn.btn-xs.btn-inverse.banner#game-menu-button(title="Show game menu", data-i18n="play_level.game_menu") Game Menu
|
||||
|
||||
|
|
12
app/templates/play/level/multiplayer-status.jade
Normal file
12
app/templates/play/level/multiplayer-status.jade
Normal file
|
@ -0,0 +1,12 @@
|
|||
//- TODO: Replace this devart with nice shinies
|
||||
|
||||
div
|
||||
button#multiplayer-button Multiplayer
|
||||
//- span.spr
|
||||
//- span.player-count #{playerCount} total players
|
||||
span.spr
|
||||
span.players-available #{playersAvailable} available
|
||||
span.spr
|
||||
span.players-unavailable #{playersUnavailable} playing
|
||||
span.spr
|
||||
span.game-status #{status}
|
|
@ -22,14 +22,16 @@ module.exports = class GameMenuModal extends ModalView
|
|||
super options
|
||||
@options.showDevBits = me.isAdmin() or /https?:\/\/localhost/.test(window.location.href)
|
||||
@options.showInventory = @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop']
|
||||
@options.showTab = options.showTab
|
||||
@options.levelID = @options.level.get('slug')
|
||||
@options.startingSessionHeroConfig = $.extend {}, true, (@options.session.get('heroConfig') ? {})
|
||||
Backbone.Mediator.publish 'music-player:enter-menu', terrain: @options.level.get('terrain', true)
|
||||
Backbone.Mediator.publish 'music-player:enter-menu', terrain: @options.level.get('terrain', true) ? 'Dungeon'
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context.showDevBits = @options.showDevBits
|
||||
context.showInventory = @options.showInventory
|
||||
context.showTab = @options.showTab
|
||||
docs = @options.level.get('documentation') ? {}
|
||||
context.showsGuide = docs.specificArticles?.length or docs.generalArticles?.length
|
||||
context
|
||||
|
@ -37,7 +39,11 @@ module.exports = class GameMenuModal extends ModalView
|
|||
afterRender: ->
|
||||
super()
|
||||
@insertSubView new submenuView @options for submenuView in submenuViews
|
||||
firstView = (if @options.showInventory then @subviews.inventory_view else @subviews.choose_hero_view)
|
||||
if @options.showTab
|
||||
firstView = switch @options.showTab
|
||||
when 'multiplayer' then @subviews.multiplayer_view
|
||||
unless firstView?
|
||||
firstView = (if @options.showInventory then @subviews.inventory_view else @subviews.choose_hero_view)
|
||||
firstView.$el.addClass 'active'
|
||||
firstView.onShown?()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
|
||||
|
|
|
@ -3,6 +3,7 @@ template = require 'templates/game-menu/multiplayer-view'
|
|||
{me} = require 'lib/auth'
|
||||
ThangType = require 'models/ThangType'
|
||||
LadderSubmissionView = require 'views/play/common/LadderSubmissionView'
|
||||
RealTimeModel = require 'models/RealTimeModel'
|
||||
RealTimeCollection = require 'collections/RealTimeCollection'
|
||||
|
||||
module.exports = class MultiplayerView extends CocoView
|
||||
|
@ -16,21 +17,21 @@ module.exports = class MultiplayerView extends CocoView
|
|||
events:
|
||||
'click textarea': 'onClickLink'
|
||||
'change #multiplayer': 'updateLinkSection'
|
||||
'click #create-game-button': 'onCreateGame'
|
||||
'click #join-game-button': 'onJoinGame'
|
||||
'click #leave-game-button': 'onLeaveGame'
|
||||
'click #create-game-button': 'onCreateRealTimeGame'
|
||||
'click #join-game-button': 'onJoinRealTimeGame'
|
||||
'click #leave-game-button': 'onLeaveRealTimeGame'
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
@level = options.level
|
||||
@session = options.session
|
||||
@listenTo @session, 'change:multiplayer', @updateLinkSection
|
||||
@initMultiplayerSessions()
|
||||
@watchRealTimeSessions()
|
||||
|
||||
destroy: ->
|
||||
@multiplayerSessions?.off()
|
||||
@currentMultiplayerSession?.off()
|
||||
collection.off() for id, collection of @playersCollections
|
||||
@realTimeSessions?.off 'add', @onRealTimeSessionAdded
|
||||
@currentRealTimeSession?.off 'change', @onCurrentRealTimeSessionChanged
|
||||
collection.off() for id, collection of @realTimeSessionsPlayers
|
||||
super()
|
||||
|
||||
getRenderData: ->
|
||||
|
@ -44,10 +45,17 @@ module.exports = class MultiplayerView extends CocoView
|
|||
c.ladderGame = true
|
||||
c.readyToRank = @session?.readyToRank()
|
||||
|
||||
# Real-time multiplayer stuff
|
||||
c.levelID = @session.get('levelID')
|
||||
c.multiplayerSessions = @multiplayerSessions.models
|
||||
c.currentMultiplayerSession = @currentMultiplayerSession if @currentMultiplayerSession
|
||||
c.playersCollections = @playersCollections if @playersCollections
|
||||
c.realTimeSessions = @realTimeSessions
|
||||
c.currentRealTimeSession = @currentRealTimeSession if @currentRealTimeSession
|
||||
c.realTimeSessionPlayers = @realTimeSessionsPlayers if @realTimeSessionsPlayers
|
||||
# console.log 'MultiplayerView getRenderData', c.levelID
|
||||
# console.log 'realTimeSessions', c.realTimeSessions
|
||||
# console.log c.realTimeSessions.at(c.realTimeSessions.length - 1).get('state') if c.realTimeSessions.length > 0
|
||||
# console.log 'currentRealTimeSession', c.currentRealTimeSession
|
||||
# console.log 'realTimeSessionPlayers', c.realTimeSessionPlayers
|
||||
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
|
@ -55,8 +63,8 @@ module.exports = class MultiplayerView extends CocoView
|
|||
@updateLinkSection()
|
||||
@ladderSubmissionView = new LadderSubmissionView session: @session, level: @level
|
||||
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
|
||||
@$el.find('#created-multiplayer-session').toggle Boolean(@currentMultiplayerSession?)
|
||||
@$el.find('#create-game-button').toggle Boolean(not (@currentMultiplayerSession?))
|
||||
@$el.find('#created-multiplayer-session').toggle Boolean(@currentRealTimeSession?)
|
||||
@$el.find('#create-game-button').toggle Boolean(not (@currentRealTimeSession?))
|
||||
|
||||
onClickLink: (e) ->
|
||||
e.target.select()
|
||||
|
@ -75,98 +83,112 @@ module.exports = class MultiplayerView extends CocoView
|
|||
multiplayer = Boolean(@$el.find('#multiplayer').prop('checked'))
|
||||
@session.set('multiplayer', multiplayer)
|
||||
|
||||
# TODO: shouldn't have to open MultiplayerView to read existing multiplayerSession?
|
||||
# TODO: if someone leaves your game, it should go back to 'creating' state
|
||||
# Real-time Multiplayer ######################################################
|
||||
#
|
||||
# This view is responsible for joining and leaving real-time multiplayer games.
|
||||
#
|
||||
# It performs these actions:
|
||||
# Display your current game (level, players)
|
||||
# Display open games
|
||||
# Create game button, if not in a game
|
||||
# Join game button
|
||||
# Leave game button, if in a game
|
||||
#
|
||||
# It monitors these:
|
||||
# Real-time multiplayer sessions (for open games, player states)
|
||||
# Current real-time multiplayer game session for changes
|
||||
# Players for real-time multiplayer game session
|
||||
#
|
||||
# Real-time state variables:
|
||||
# @realTimeSessionsPlayers - Collection of player lists for active real-time multiplayer sessions
|
||||
# @realTimeSessions - Active real-time multiplayer sessions
|
||||
# @currentRealTimeSession - Our current real-time multiplayer session
|
||||
|
||||
initMultiplayerSessions: ->
|
||||
@playersCollections = {}
|
||||
watchRealTimeSessions: ->
|
||||
# Setup monitoring of real-time multiplayer level sessions
|
||||
@realTimeSessionsPlayers = {}
|
||||
# TODO: only request sessions for this level, !team, etc.
|
||||
# TODO: don't hard code this path all over the place
|
||||
@multiplayerSessions = new RealTimeCollection('multiplayer_level_sessions/')
|
||||
@multiplayerSessions.on 'add', @onMultiplayerSessionAdded
|
||||
@multiplayerSessions.on 'remove', @onMultiplayerSessionRemoved
|
||||
@multiplayerSessions.each (ms) => @initMultiplayerSession ms
|
||||
# TODO: move this to multiplayer_level_sessions/#{levelID}/
|
||||
@realTimeSessions = new RealTimeCollection('multiplayer_level_sessions/')
|
||||
@realTimeSessions.on 'add', @onRealTimeSessionAdded
|
||||
@realTimeSessions.each (rts) => @watchRealTimeSession rts
|
||||
|
||||
initMultiplayerSession: (ms) ->
|
||||
# TODO: double check these players events are needed on top of onMultiplayerSessionChanged
|
||||
@playersCollections[ms.id] = new RealTimeCollection('multiplayer_level_sessions/' + ms.id + '/players')
|
||||
@playersCollections[ms.id].on 'add', @onPlayerAdded
|
||||
@playersCollections[ms.id].on 'remove', @onPlayerRemoved
|
||||
if not @currentMultiplayerSession and ms.get('levelID') is @session.get('levelID')
|
||||
@playersCollections[ms.id].each (player) =>
|
||||
if player.id is me.id and player.get('team') is @session.get('team')
|
||||
@currentMultiplayerSession = ms
|
||||
@currentMultiplayerSession.on 'change', @onMultiplayerSessionChanged
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:joined-game', session: @currentMultiplayerSession
|
||||
watchRealTimeSession: (rts) ->
|
||||
return if rts.get('state') is 'finished'
|
||||
return if rts.get('levelID') isnt @session.get('levelID')
|
||||
# console.log 'MultiplayerView watchRealTimeSession', rts
|
||||
# Setup monitoring of players for given session
|
||||
# TODO: verify we need this
|
||||
realTimeSession = new RealTimeModel('multiplayer_level_sessions/' + rts.id)
|
||||
realTimeSession.on 'change', @onRealTimeSessionChanged
|
||||
@realTimeSessionsPlayers[rts.id] = new RealTimeCollection('multiplayer_level_sessions/' + rts.id + '/players')
|
||||
@realTimeSessionsPlayers[rts.id].on 'add', @onRealTimePlayerAdded
|
||||
@findCurrentRealTimeSession rts
|
||||
|
||||
onMultiplayerSessionAdded: (e) =>
|
||||
#console.log 'onMultiplayerSessionAdded', e
|
||||
@initMultiplayerSession e
|
||||
findCurrentRealTimeSession: (rts) ->
|
||||
# Look for our current real-time session (level, level state, member player)
|
||||
return if @currentRealTimeSession or not @realTimeSessionsPlayers?
|
||||
if rts.get('levelID') is @session.get('levelID') and rts.get('state') isnt 'finished'
|
||||
@realTimeSessionsPlayers[rts.id].each (player) =>
|
||||
if player.id is me.id and player.get('state') isnt 'left'
|
||||
# console.log 'MultiplayerView found current real-time session', rts
|
||||
@currentRealTimeSession = new RealTimeModel('multiplayer_level_sessions/' + rts.id)
|
||||
@currentRealTimeSession.on 'change', @onCurrentRealTimeSessionChanged
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:joined-game', id: me.id, session: @currentRealTimeSession
|
||||
|
||||
onRealTimeSessionAdded: (rts) =>
|
||||
@watchRealTimeSession rts
|
||||
@render()
|
||||
|
||||
onMultiplayerSessionRemoved: (e) =>
|
||||
@playersCollections[e.id].off()
|
||||
delete @playersCollections[e.id]
|
||||
@render()
|
||||
|
||||
onMultiplayerSessionChanged: (e) =>
|
||||
@render()
|
||||
|
||||
onPlayerAdded: (e) =>
|
||||
# TODO: listeners not being unhooked
|
||||
onRealTimeSessionChanged: (rts) =>
|
||||
# console.log 'MultiplayerView onRealTimeSessionChanged', rts.get('state')
|
||||
# TODO: @realTimeSessions isn't updated before we call render() here
|
||||
# TODO: so this game isn't updated in open games list
|
||||
@render?()
|
||||
|
||||
onPlayerRemoved: (e) =>
|
||||
# TODO: listeners not being unhooked
|
||||
onCurrentRealTimeSessionChanged: (rts) =>
|
||||
# console.log 'MultiplayerView onCurrentRealTimeSessionChanged', rts
|
||||
if rts.get('state') is 'finished'
|
||||
@currentRealTimeSession.off 'change', @onCurrentRealTimeSessionChanged
|
||||
@currentRealTimeSession = null
|
||||
@render?()
|
||||
|
||||
onCreateGame: ->
|
||||
s = @multiplayerSessions.create {
|
||||
onRealTimePlayerAdded: (e) =>
|
||||
@render?()
|
||||
|
||||
onCreateRealTimeGame: ->
|
||||
s = @realTimeSessions.create {
|
||||
creator: @session.get('creator')
|
||||
creatorName: @session.get('creatorName')
|
||||
levelID: @session.get('levelID')
|
||||
created: (new Date()).toISOString()
|
||||
state: 'creating'
|
||||
}
|
||||
@currentMultiplayerSession = @multiplayerSessions.get(s.id)
|
||||
@currentMultiplayerSession.on 'change', @onMultiplayerSessionChanged
|
||||
players = new RealTimeCollection('multiplayer_level_sessions/' + @currentMultiplayerSession.id + '/players')
|
||||
players.create {id: me.id, name: @session.get('creatorName'), team: @session.get('team')}
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:joined-game', session: @currentMultiplayerSession
|
||||
@currentRealTimeSession = @realTimeSessions.get(s.id)
|
||||
@currentRealTimeSession.on 'change', @onCurrentRealTimeSessionChanged
|
||||
# TODO: s.id === @currentRealTimeSession.id ?
|
||||
players = new RealTimeCollection('multiplayer_level_sessions/' + @currentRealTimeSession.id + '/players')
|
||||
players.create id: me.id, state: 'coding', name: @session.get('creatorName'), team: @session.get('team')
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:created-game', session: @currentRealTimeSession
|
||||
@render()
|
||||
|
||||
onJoinGame: (e) ->
|
||||
return if @currentMultiplayerSession
|
||||
onJoinRealTimeGame: (e) ->
|
||||
return if @currentRealTimeSession
|
||||
item = @$el.find(e.target).data('item')
|
||||
@currentMultiplayerSession = @multiplayerSessions.get(item.id)
|
||||
@currentMultiplayerSession.on 'change', @onMultiplayerSessionChanged
|
||||
if @playersCollections[item.id]
|
||||
@playersCollections[item.id].create {id: me.id, name: @session.get('creatorName'), team: @session.get('team')}
|
||||
@currentRealTimeSession = @realTimeSessions.get(item.id)
|
||||
@currentRealTimeSession.on 'change', @onCurrentRealTimeSessionChanged
|
||||
if @realTimeSessionsPlayers[item.id]
|
||||
@realTimeSessionsPlayers[item.id].create id: me.id, state: 'coding', name: @session.get('creatorName'), team: @session.get('team')
|
||||
else
|
||||
console.error 'onJoinGame did not have a players collection', @currentMultiplayerSession
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:joined-game', session: @currentMultiplayerSession
|
||||
if @playersCollections[item.id]?.length is 2
|
||||
@currentMultiplayerSession.set 'state', 'coding'
|
||||
# TODO: close multiplayer view?
|
||||
console.error 'MultiplayerView onJoinRealTimeGame did not have a players collection', @currentRealTimeSession
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:joined-game', id: me.id, session: @currentRealTimeSession
|
||||
@render()
|
||||
|
||||
onLeaveGame: (e) ->
|
||||
# TODO: This doesn't update open games or current game
|
||||
if @currentMultiplayerSession
|
||||
players = @playersCollections[@currentMultiplayerSession.id]
|
||||
for i in [0...players.length]
|
||||
player = players.at(i)
|
||||
if player.get('id') is me.id
|
||||
players.remove(player)
|
||||
# NOTE: remove(@something) doesn't stick locally, only remotely
|
||||
cms = @currentMultiplayerSession
|
||||
@currentMultiplayerSession.off()
|
||||
@currentMultiplayerSession = null
|
||||
if players.length is 0
|
||||
@multiplayerSessions.remove(cms)
|
||||
break
|
||||
console.error "Tried to leave a game we hadn't joined!" if @currentMultiplayerSession
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:left-game', {}
|
||||
onLeaveRealTimeGame: (e) ->
|
||||
if @currentRealTimeSession
|
||||
@currentRealTimeSession.off 'change', @onCurrentRealTimeSessionChanged
|
||||
@currentRealTimeSession = null
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:left-game', id: me.id
|
||||
else
|
||||
console.error "Tried to leave a game with no currentMultiplayerSession"
|
||||
@render()
|
||||
|
|
|
@ -889,6 +889,8 @@ forest = [
|
|||
id: 'defense-of-plainswood'
|
||||
original: '541b67f71ccc8eaae19f3c62'
|
||||
description: 'Protect the peasants from the pursuing ogres.'
|
||||
nextLevels:
|
||||
continue: 'winding-trail'
|
||||
x: 29.63
|
||||
y: 53.69
|
||||
}
|
||||
|
@ -899,6 +901,8 @@ forest = [
|
|||
id: 'winding-trail'
|
||||
original: '5446cb40ce01c23e05ecf027'
|
||||
description: 'Stay alive and navigate through the forest.'
|
||||
nextLevels:
|
||||
continue: 'thornbush-farm'
|
||||
x: 39.03
|
||||
y: 54.97
|
||||
}
|
||||
|
@ -909,6 +913,8 @@ forest = [
|
|||
id: 'thornbush-farm'
|
||||
original: '5447030525cce60000745e2a'
|
||||
description: 'Determine refugee peasant from ogre when defending the farm.'
|
||||
nextLevels:
|
||||
continue: 'a-fiery-trap'
|
||||
x: 44.09
|
||||
y: 57.75
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@ module.exports = class ControlBarView extends CocoView
|
|||
|
||||
subscriptions:
|
||||
'bus:player-states-changed': 'onPlayerStatesChanged'
|
||||
'real-time-multiplayer:joined-game': 'onJoinedRealTimeMultiplayerGame'
|
||||
'real-time-multiplayer:left-game': 'onLeftRealTimeMultiplayerGame'
|
||||
|
||||
events:
|
||||
'click #next-game-button': -> Backbone.Mediator.publish 'level:next-game-pressed', {}
|
||||
|
@ -62,9 +60,6 @@ module.exports = class ControlBarView extends CocoView
|
|||
@homeLink = c.homeLink = '/'
|
||||
@homeViewClass = require 'views/HomeView'
|
||||
c.editorLink = "/editor/level/#{@level.get('slug')}"
|
||||
c.multiplayerSession = @multiplayerSession if @multiplayerSession
|
||||
c.multiplayerPlayers = @multiplayerPlayers if @multiplayerPlayers
|
||||
c.meID = me.id
|
||||
c
|
||||
|
||||
showGameMenuModal: ->
|
||||
|
@ -74,22 +69,3 @@ module.exports = class ControlBarView extends CocoView
|
|||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
Backbone.Mediator.publish 'router:navigate', route: @homeLink, viewClass: @homeViewClass, viewArgs: @homeViewArgs
|
||||
|
||||
onJoinedRealTimeMultiplayerGame: (e) ->
|
||||
@multiplayerSession = e.session
|
||||
@multiplayerPlayers = new RealTimeCollection('multiplayer_level_sessions/' + @multiplayerSession.id + '/players')
|
||||
@multiplayerPlayers.on 'add', @onRealTimeMultiplayerPlayerAdded
|
||||
@multiplayerPlayers.on 'remove', @onRealTimeMultiplayerPlayerRemoved
|
||||
@render()
|
||||
|
||||
onLeftRealTimeMultiplayerGame: (e) ->
|
||||
@multiplayerSession = null
|
||||
@multiplayerPlayers.off()
|
||||
@multiplayerPlayers = null
|
||||
@render()
|
||||
|
||||
onRealTimeMultiplayerPlayerAdded: (e) =>
|
||||
@render() unless @destroyed
|
||||
|
||||
onRealTimeMultiplayerPlayerRemoved: (e) =>
|
||||
@render() unless @destroyed
|
||||
|
|
93
app/views/play/level/MultiplayerStatusView.coffee
Normal file
93
app/views/play/level/MultiplayerStatusView.coffee
Normal file
|
@ -0,0 +1,93 @@
|
|||
CocoView = require 'views/kinds/CocoView'
|
||||
template = require 'templates/play/level/multiplayer-status'
|
||||
{me} = require 'lib/auth'
|
||||
RealTimeModel = require 'models/RealTimeModel'
|
||||
RealTimeCollection = require 'collections/RealTimeCollection'
|
||||
GameMenuModal = require 'views/game-menu/GameMenuModal'
|
||||
|
||||
# Real-time Multiplayer ######################################################
|
||||
#
|
||||
# This view displays the real-time multiplayer status for the current level.
|
||||
#
|
||||
# It performs these actions:
|
||||
# Multiplayer button into game-menu multiplayer section
|
||||
# Display number of players waiting for an opponent in this level
|
||||
# Display number of players current playing a pvp game in this level
|
||||
# Status for user's current real-time multiplayer session
|
||||
#
|
||||
# It monitors these:
|
||||
# Real-time multiplayer players
|
||||
# Internal multiplayer status
|
||||
#
|
||||
# Real-time state variables:
|
||||
# @playersCollection - Real-time multiplayer players
|
||||
|
||||
module.exports = class MultiplayerStatusView extends CocoView
|
||||
id: 'multiplayer-status-view'
|
||||
template: template
|
||||
|
||||
subscriptions:
|
||||
'real-time-multiplayer:player-status': 'onRealTimeMultiplayerPlayerStatus'
|
||||
|
||||
events:
|
||||
'click #multiplayer-button': 'onClickMultiplayerButton'
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
@session = options.session
|
||||
@level = options.level
|
||||
@levelID = options.levelID
|
||||
@status = ''
|
||||
@players = {}
|
||||
@playersCollection = new RealTimeCollection('multiplayer_players/' + @levelID)
|
||||
@playersCollection.on 'add', @onPlayerAdded
|
||||
@playersCollection.each (player) => @onPlayerAdded player
|
||||
|
||||
destroy: ->
|
||||
@playersCollection?.off 'add', @onPlayerAdded
|
||||
player.off 'change', @onPlayerChanged for id, player of @players
|
||||
super()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.playerCount = @playerCount
|
||||
c.playersAvailable = @playersCollectionAvailable
|
||||
c.playersUnavailable = @playersCollectionUnavailable
|
||||
c.status = @status
|
||||
c
|
||||
|
||||
onRealTimeMultiplayerPlayerStatus: (e) ->
|
||||
@status = e.status
|
||||
@render?()
|
||||
|
||||
onClickMultiplayerButton: (e) ->
|
||||
@openModalView new GameMenuModal showTab: 'multiplayer', level: @level, session: @session, supermodel: @supermodel
|
||||
|
||||
onPlayerAdded: (player) =>
|
||||
# console.log 'MultiplayerStatusView onPlayerAdded', player
|
||||
unless player.id is me.id
|
||||
@players[player.id] = new RealTimeModel('multiplayer_players/' + @levelID + '/' + player.id)
|
||||
@players[player.id].on 'change', @onPlayerChanged
|
||||
@countPlayers player
|
||||
|
||||
onPlayerChanged: (player) =>
|
||||
# console.log 'MultiplayerStatusView onPlayerChanged', player
|
||||
@countPlayers player
|
||||
|
||||
countPlayers: (changedPlayer) =>
|
||||
# TODO: save this stale hearbeat threshold setting somewhere
|
||||
staleHeartbeat = new Date()
|
||||
staleHeartbeat.setMinutes staleHeartbeat.getMinutes() - 3
|
||||
@playerCount = 0
|
||||
@playersCollectionAvailable = 0
|
||||
@playersCollectionUnavailable = 0
|
||||
@playersCollection.each (player) =>
|
||||
# Assume changedPlayer is fresher than entry in @playersCollection collection
|
||||
player = changedPlayer if changedPlayer? and player.id is changedPlayer.id
|
||||
unless staleHeartbeat >= new Date(player.get('heartbeat'))
|
||||
@playerCount++
|
||||
@playersCollectionAvailable++ if player.get('state') is 'available'
|
||||
@playersCollectionUnavailable++ if player.get('state') is 'unavailable'
|
||||
# console.log 'MultiplayerStatusView countPlayers', @playerCount, @playersCollectionAvailable, @playersCollectionUnavailable
|
||||
@render()
|
||||
|
|
@ -35,6 +35,7 @@ VictoryModal = require './modal/VictoryModal'
|
|||
HeroVictoryModal = require './modal/HeroVictoryModal'
|
||||
InfiniteLoopModal = require './modal/InfiniteLoopModal'
|
||||
GameMenuModal = require 'views/game-menu/GameMenuModal'
|
||||
MultiplayerStatusView = require './MultiplayerStatusView'
|
||||
|
||||
PROFILE_ME = false
|
||||
|
||||
|
@ -71,8 +72,9 @@ module.exports = class PlayLevelView extends RootView
|
|||
'playback:real-time-playback-waiting': 'onRealTimePlaybackWaiting'
|
||||
'playback:real-time-playback-started': 'onRealTimePlaybackStarted'
|
||||
'playback:real-time-playback-ended': 'onRealTimePlaybackEnded'
|
||||
'real-time-multiplayer:joined-game': 'onJoinedRealTimeMultiplayerGame'
|
||||
'real-time-multiplayer:left-game': 'onLeftRealTimeMultiplayerGame'
|
||||
'real-time-multiplayer:created-game': 'onRealTimeMultiplayerCreatedGame'
|
||||
'real-time-multiplayer:joined-game': 'onRealTimeMultiplayerJoinedGame'
|
||||
'real-time-multiplayer:left-game': 'onRealTimeMultiplayerLeftGame'
|
||||
'real-time-multiplayer:manual-cast': 'onRealTimeMultiplayerCast'
|
||||
'level:hero-config-changed': 'onHeroConfigChanged'
|
||||
|
||||
|
@ -244,6 +246,8 @@ module.exports = class PlayLevelView extends RootView
|
|||
@insertSubView new GoldView {}
|
||||
@insertSubView new HUDView {level: @level}
|
||||
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
||||
if @level.get('type') in ['ladder', 'hero-ladder']
|
||||
@insertSubView new MultiplayerStatusView levelID: @levelID, session: @session, level: @level
|
||||
worldName = utils.i18n @level.attributes, 'name'
|
||||
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel}
|
||||
#_.delay (=> Backbone.Mediator.publish('level:set-debug', debug: true)), 5000 if @isIPadApp() # if me.displayName() is 'Nick'
|
||||
|
@ -273,6 +277,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
# Just the level and session have been loaded by the level loader
|
||||
if e.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop'] and not _.size e.session.get('heroConfig')?.inventory ? {}
|
||||
@openModalView new GameMenuModal level: e.level, session: e.session, supermodel: @supermodel
|
||||
@onRealTimeMultiplayerLevelLoaded e.session if e.level.get('type') in ['ladder', 'hero-ladder']
|
||||
|
||||
onLoaded: ->
|
||||
_.defer => @onLevelLoaderLoaded()
|
||||
|
@ -554,29 +559,159 @@ module.exports = class PlayLevelView extends RootView
|
|||
#@instance.save() unless @instance.loading
|
||||
delete window.nextLevelURL
|
||||
console.profileEnd?() if PROFILE_ME
|
||||
@onRealTimeMultiplayerLevelUnloaded()
|
||||
super()
|
||||
|
||||
# Real-time Multiplayer ######################################################
|
||||
#
|
||||
# This view acts as a hub for the real-time multiplayer session for the current level.
|
||||
#
|
||||
# It performs these actions:
|
||||
# Player heartbeat
|
||||
# Publishes player status
|
||||
# Updates real-time multiplayer session state
|
||||
# Updates real-time multiplayer player state
|
||||
# Cleans up old sessions (sets state to 'finished')
|
||||
# Real-time multiplayer cast handshake
|
||||
#
|
||||
# It monitors these:
|
||||
# Real-time multiplayer sessions
|
||||
# Current real-time multiplayer session
|
||||
# Internal multiplayer create/joined/left events
|
||||
#
|
||||
# Real-time state variables:
|
||||
# @realTimePlayerStatus - User's real-time multiplayer state for this level
|
||||
# @realTimePlayerGameStatus - User's state for current real-time multiplayer game session
|
||||
# @realTimeSession - Current real-time multiplayer game session
|
||||
# @realTimeOpponent - Current real-time multiplayer opponent
|
||||
# @realTimePlayers - Real-time players for current real-time multiplayer game session
|
||||
# @realTimeSessionCollection - Collection of all real-time multiplayer sessions
|
||||
#
|
||||
# TODO: Move this code to it's own file, or possibly the LevelBus
|
||||
# TODO: save settings somewhere reasonable
|
||||
|
||||
onRealTimeMultiplayerPlaybackEnded: ->
|
||||
if @multiplayerSession
|
||||
@multiplayerSession.set 'state', 'coding'
|
||||
players = new RealTimeCollection('multiplayer_level_sessions/' + @multiplayerSession.id + '/players')
|
||||
players.each (player) -> player.set 'state', 'coding' if player.id is me.id
|
||||
onRealTimeMultiplayerLevelLoaded: (session) ->
|
||||
return if me.get('anonymous')
|
||||
players = new RealTimeCollection('multiplayer_players/' + @levelID)
|
||||
players.create
|
||||
id: me.id
|
||||
name: session.get('creatorName')
|
||||
state: 'playing'
|
||||
created: new Date().toISOString()
|
||||
heartbeat: new Date().toISOString()
|
||||
@realTimePlayerStatus = new RealTimeModel('multiplayer_players/' + @levelID + '/' + me.id)
|
||||
@timerMultiplayerHeartbeatID = setInterval @onRealTimeMultiplayerHeartbeat, 60 * 1000
|
||||
@cleanupRealTimeSessions()
|
||||
|
||||
onJoinedRealTimeMultiplayerGame: (e) ->
|
||||
@multiplayerSession = new RealTimeModel('multiplayer_level_sessions/' + e.session.id)
|
||||
cleanupRealTimeSessions: ->
|
||||
@realTimeSessionCollection = new RealTimeCollection 'multiplayer_level_sessions'
|
||||
@realTimeSessionCollection.on 'add', @cleanupRealTimeSession
|
||||
@realTimeSessionCollection.each @cleanupRealTimeSession
|
||||
|
||||
onLeftRealTimeMultiplayerGame: (e) ->
|
||||
if @multiplayerSession
|
||||
@multiplayerSession.off()
|
||||
@multiplayerSession = null
|
||||
cleanupRealTimeSession: (session) =>
|
||||
if session.get('state') isnt 'finished'
|
||||
players = new RealTimeCollection 'multiplayer_level_sessions/' + session.id + '/players'
|
||||
players.each (player) =>
|
||||
if player.id is me.id
|
||||
p = new RealTimeModel 'multiplayer_level_sessions/' + session.id + '/players/' + me.id
|
||||
console.info 'Cleaning up previous real-time multiplayer session', session.id
|
||||
p.set 'state', 'left'
|
||||
session.set 'state', 'finished'
|
||||
|
||||
onRealTimeMultiplayerLevelUnloaded: ->
|
||||
clearInterval @timerMultiplayerHeartbeatID if @timerMultiplayerHeartbeatID?
|
||||
if @realTimeSessionCollection?
|
||||
@realTimeSessionCollection.off 'add', @cleanupRealTimeSession
|
||||
@realTimeSessionCollection = null
|
||||
|
||||
onRealTimeMultiplayerHeartbeat: =>
|
||||
@realTimePlayerStatus.set 'heartbeat', new Date().toISOString() if @realTimePlayerStatus
|
||||
|
||||
onRealTimeMultiplayerCreatedGame: (e) ->
|
||||
# Watch external multiplayer session
|
||||
@realTimeSession = new RealTimeModel 'multiplayer_level_sessions/' + e.session.id
|
||||
@realTimeSession.on 'change', @onRealTimeSessionChanged
|
||||
@realTimePlayers = new RealTimeCollection 'multiplayer_level_sessions/' + e.session.id + '/players'
|
||||
@realTimePlayers.on 'add', @onRealTimePlayerAdded
|
||||
@realTimePlayerGameStatus = new RealTimeModel 'multiplayer_level_sessions/' + e.session.id + '/players/' + me.id
|
||||
@realTimePlayerGameStatus.set 'state', 'coding'
|
||||
@realTimePlayerStatus.set 'state', 'available'
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: 'Waiting for opponent..'
|
||||
|
||||
onRealTimeSessionChanged: (e) =>
|
||||
# console.log 'PlayLevelView onRealTimeSessionChanged', e
|
||||
if e.get('state') is 'finished'
|
||||
@realTimeGameEnded()
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:left-game', {}
|
||||
|
||||
onRealTimePlayerAdded: (e) =>
|
||||
# console.log 'PlayLevelView onRealTimePlayerAdded', e
|
||||
# Assume game is full, game on
|
||||
if @realTimeSession.get('state') is 'creating'
|
||||
@realTimeSession.set 'state', 'coding'
|
||||
@realTimePlayerStatus.set 'state', 'unavailable'
|
||||
@realTimeOpponent = new RealTimeModel('multiplayer_level_sessions/' + @realTimeSession.id + '/players/' + e.id)
|
||||
@realTimeOpponent.on 'change', @onRealTimeOpponentChanged
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: 'Playing against ' + e.get('name')
|
||||
else
|
||||
console.error 'PlayLevelView onRealTimePlayerAdded session in unexpected state', @realTimeSession.get('state')
|
||||
|
||||
onRealTimeOpponentChanged: (e) =>
|
||||
# console.log 'PlayLevelView onRealTimeOpponentChanged', e
|
||||
switch @realTimeOpponent.get('state')
|
||||
when 'left'
|
||||
console.info 'Real-time multiplayer opponent left the game'
|
||||
opponentID = @realTimeOpponent.id
|
||||
@realTimeGameEnded()
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:left-game', id: opponentID
|
||||
when 'submitted'
|
||||
# TODO: What should this message say?
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: @realTimeOpponent.get('name') + ' waiting for your code..'
|
||||
|
||||
onRealTimeMultiplayerJoinedGame: (e) ->
|
||||
# console.log 'PlayLevelView onRealTimeMultiplayerJoinedGame', e
|
||||
if e.id is me.id
|
||||
@realTimeSession = new RealTimeModel 'multiplayer_level_sessions/' + e.session.id
|
||||
@realTimeSession.set 'state', 'coding'
|
||||
@realTimeSession.on 'change', @onRealTimeSessionChanged
|
||||
@realTimePlayers = new RealTimeCollection 'multiplayer_level_sessions/' + e.session.id + '/players'
|
||||
@realTimePlayers.on 'add', @onRealTimePlayerAdded
|
||||
@realTimePlayerGameStatus = new RealTimeModel 'multiplayer_level_sessions/' + e.session.id + '/players/' + me.id
|
||||
@realTimePlayerGameStatus.set 'state', 'coding'
|
||||
@realTimePlayerStatus.set 'state', 'unavailable'
|
||||
for id, player of e.session.get('players')
|
||||
if id isnt me.id
|
||||
@realTimeOpponent = new RealTimeModel 'multiplayer_level_sessions/' + e.session.id + '/players/' + id
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: 'Playing against ' + player.name
|
||||
|
||||
onRealTimeMultiplayerLeftGame: (e) ->
|
||||
# console.log 'PlayLevelView onRealTimeMultiplayerLeftGame', e
|
||||
if e.id? and e.id is me.id
|
||||
@realTimePlayerGameStatus.set 'state', 'left'
|
||||
@realTimeGameEnded()
|
||||
|
||||
realTimeGameEnded: ->
|
||||
if @realTimeOpponent?
|
||||
@realTimeOpponent.off 'change', @onRealTimeOpponentChanged
|
||||
@realTimeOpponent = null
|
||||
if @realTimePlayers?
|
||||
@realTimePlayers.off 'add', @onRealTimePlayerAdded
|
||||
@realTimePlayers = null
|
||||
if @realTimeSession?
|
||||
@realTimeSession.off 'change', @onRealTimeSessionChanged
|
||||
@realTimeSession.set 'state', 'finished'
|
||||
@realTimeSession = null
|
||||
if @realTimePlayerGameStatus?
|
||||
@realTimePlayerGameStatus = null
|
||||
if @realTimePlayerStatus?
|
||||
@realTimePlayerStatus.set 'state', 'playing'
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: ''
|
||||
|
||||
onRealTimeMultiplayerCast: (e) ->
|
||||
unless @multiplayerSession
|
||||
unless @realTimeSession
|
||||
console.error 'onRealTimeMultiplayerCast without a multiplayerSession'
|
||||
return
|
||||
players = new RealTimeCollection('multiplayer_level_sessions/' + @multiplayerSession.id + '/players')
|
||||
players = new RealTimeCollection('multiplayer_level_sessions/' + @realTimeSession.id + '/players')
|
||||
myPlayer = opponentPlayer = null
|
||||
players.each (player) ->
|
||||
if player.id is me.id
|
||||
|
@ -596,26 +731,36 @@ module.exports = class PlayLevelView extends RootView
|
|||
state = opponentPlayer.get('state')
|
||||
console.info 'Other player is', state
|
||||
if state in ['submitted', 'ready']
|
||||
@onOpponentSubmitted(opponentPlayer, myPlayer)
|
||||
@realTimeOpponentSubmittedCode opponentPlayer, myPlayer
|
||||
else
|
||||
# Wait for opponent to submit their code
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: 'Waiting for code from ' + @realTimeOpponent.get('name')
|
||||
opponentPlayer.on 'change', (e) =>
|
||||
state = opponentPlayer.get('state')
|
||||
if state in ['submitted', 'ready']
|
||||
@onOpponentSubmitted(opponentPlayer, myPlayer)
|
||||
@realTimeOpponentSubmittedCode opponentPlayer, myPlayer
|
||||
|
||||
onOpponentSubmitted: (opponentPlayer, myPlayer) =>
|
||||
onRealTimeMultiplayerPlaybackEnded: ->
|
||||
if @realTimeSession?
|
||||
@realTimeSession.set 'state', 'coding'
|
||||
@realTimePlayers.each (player) -> player.set 'state', 'coding' if player.id is me.id
|
||||
if @realTimeOpponent?
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: 'Playing against ' + @realTimeOpponent.get('name')
|
||||
|
||||
realTimeOpponentSubmittedCode: (opponentPlayer, myPlayer) =>
|
||||
# Save opponent's code
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:new-opponent-code', {codeLanguage: opponentPlayer.get('codeLanguage'), code: opponentPlayer.get('code'), team: opponentPlayer.get('team')}
|
||||
# I'm ready to rumble
|
||||
myPlayer.set 'state', 'ready'
|
||||
if opponentPlayer.get('state') is 'ready'
|
||||
console.info 'All real-time multiplayer players are ready!'
|
||||
@multiplayerSession.set 'state', 'running'
|
||||
@realTimeSession.set 'state', 'running'
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: 'Battling ' + @realTimeOpponent.get('name')
|
||||
else
|
||||
# Wait for opponent to be ready
|
||||
opponentPlayer.on 'change', (e) =>
|
||||
if opponentPlayer.get('state') is 'ready'
|
||||
opponentPlayer.off()
|
||||
opponentPlayer.off 'change'
|
||||
console.info 'All real-time multiplayer players are ready!'
|
||||
@multiplayerSession.set 'state', 'running'
|
||||
@realTimeSession.set 'state', 'running'
|
||||
Backbone.Mediator.publish 'real-time-multiplayer:player-status', status: 'Battling ' + @realTimeOpponent.get('name')
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = class CastButtonView extends CocoView
|
|||
'tome:spell-changed': 'onSpellChanged'
|
||||
'tome:cast-spells': 'onCastSpells'
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'real-time-multiplayer:created-game': 'onJoinedRealTimeMultiplayerGame'
|
||||
'real-time-multiplayer:joined-game': 'onJoinedRealTimeMultiplayerGame'
|
||||
'real-time-multiplayer:left-game': 'onLeftRealTimeMultiplayerGame'
|
||||
'goal-manager:new-goal-states': 'onNewGoalStates'
|
||||
|
@ -57,7 +58,7 @@ module.exports = class CastButtonView extends CocoView
|
|||
@multiplayerSession.on 'change', (e) =>
|
||||
if @multiplayerSession.get('state') is 'running'
|
||||
# Real-time multiplayer session is ready to go, so resume normal cast
|
||||
@multiplayerSession.off()
|
||||
@multiplayerSession.off 'change'
|
||||
Backbone.Mediator.publish 'tome:manual-cast', {realTime: true}
|
||||
else
|
||||
Backbone.Mediator.publish 'tome:manual-cast', {realTime: true}
|
||||
|
@ -128,5 +129,5 @@ module.exports = class CastButtonView extends CocoView
|
|||
|
||||
onLeftRealTimeMultiplayerGame: (e) ->
|
||||
if @multiplayerSession
|
||||
@multiplayerSession.off()
|
||||
@multiplayerSession.off 'change'
|
||||
@multiplayerSession = null
|
||||
|
|
|
@ -187,7 +187,9 @@ module.exports = class SpellPaletteView extends CocoView
|
|||
itemsByProp = {}
|
||||
for slot, inventoryID of @thang.inventoryIDs ? {}
|
||||
if item = itemThangTypes[inventoryID]
|
||||
for component in item.get('components') when component.config
|
||||
unless item.get('components')
|
||||
console.error 'Item', item, 'did not have any components when we went to assemble docs.'
|
||||
for component in item.get('components') ? [] when component.config
|
||||
for owner, storages of propStorage
|
||||
if props = component.config[storages]
|
||||
for prop in _.sortBy(props) when prop[0] isnt '_' # no private properties
|
||||
|
|
Loading…
Reference in a new issue