codecombat/app/views/play/level/LevelHUDView.coffee

184 lines
6.5 KiB
CoffeeScript
Raw Normal View History

2014-07-17 20:20:11 -04:00
CocoView = require 'views/kinds/CocoView'
2014-01-03 13:32:13 -05:00
template = require 'templates/play/level/hud'
prop_template = require 'templates/play/level/hud_prop'
LevelOptions = require 'lib/LevelOptions'
2014-01-03 13:32:13 -05:00
module.exports = class LevelHUDView extends CocoView
2014-01-03 13:32:13 -05:00
id: 'thang-hud'
template: template
subscriptions:
'surface:frame-changed': 'onFrameChanged'
'level:disable-controls': 'onDisableControls'
'level:enable-controls': 'onEnableControls'
2014-01-03 13:32:13 -05:00
'surface:sprite-selected': 'onSpriteSelected'
'sprite:thang-began-talking': 'onThangBeganTalking'
'sprite:thang-finished-talking': 'onThangFinishedTalking'
'god:new-world-created': 'onNewWorld'
2014-01-03 13:32:13 -05:00
events:
'click': 'onClick'
2014-01-03 13:32:13 -05:00
2014-02-11 17:58:45 -05:00
afterRender: ->
2014-01-09 14:04:22 -05:00
super()
@$el.addClass 'no-selection'
if LevelOptions[@options.level.get('slug')]?.hidesHUD
2014-10-30 19:59:32 -04:00
@hidesHUD = true
@$el.addClass 'hide-hud-properties'
2014-01-09 14:04:22 -05:00
onClick: (e) ->
Backbone.Mediator.publish 'tome:focus-editor', {} unless $(e.target).parents('.thang-props').length
2014-01-03 13:32:13 -05:00
onFrameChanged: (e) ->
@timeProgress = e.progress
@update()
onDisableControls: (e) ->
return if e.controls and not ('hud' in e.controls)
@disabled = true
@$el.addClass 'controls-disabled'
2014-01-03 13:32:13 -05:00
onEnableControls: (e) ->
return if e.controls and not ('hud' in e.controls)
@disabled = false
@$el.removeClass 'controls-disabled'
2014-01-03 13:32:13 -05:00
onSpriteSelected: (e) ->
return if @disabled
2014-01-09 14:04:22 -05:00
@setThang e.thang, e.sprite?.thangType
2014-01-03 13:32:13 -05:00
onNewWorld: (e) ->
hadThang = @thang
@thang = e.world.thangMap[@thang.id] if @thang
if hadThang and not @thang
@setThang null, null
2014-01-09 14:04:22 -05:00
setThang: (thang, thangType) ->
if not thang? and not @thang? then return
if thang? and @thang? and thang.id is @thang.id then return
2014-01-03 13:32:13 -05:00
@thang = thang
2014-01-09 14:04:22 -05:00
@thangType = thangType
return unless @thang
2014-01-15 18:16:31 -05:00
@createAvatar thangType, @thang
2014-01-03 13:32:13 -05:00
@createProperties()
@update()
createAvatar: (thangType, thang, colorConfig) ->
unless thangType.isFullyLoaded()
args = arguments
unless @listeningToCreateAvatar
@listenToOnce thangType, 'sync', -> @createAvatar(args...)
@listeningToCreateAvatar = true
return
@listeningToCreateAvatar = false
options = thang.getLankOptions() or {}
2014-01-15 18:16:31 -05:00
options.async = false
options.colorConfig = colorConfig if colorConfig
2014-01-09 14:04:22 -05:00
wrapper = @$el.find '.thang-canvas-wrapper'
team = @thang?.team
wrapper.removeClass (i, css) -> (css.match(/\bteam-\S+/g) or []).join ' '
wrapper.addClass "team-#{team}"
if thangType.get('raster')
wrapper.empty().append($('<img draggable="false"/>').addClass('avatar').attr('src', '/file/'+thangType.get('raster')))
else
return unless stage = thangType.getPortraitStage options, 100
newCanvas = $(stage.canvas).addClass('thang-canvas avatar')
wrapper.empty().append(newCanvas)
stage.update()
@stage?.stopTalking()
@stage = stage
wrapper.append($('<img draggable="false" />').addClass('avatar-frame').attr('src', '/images/level/thang_avatar_frame.png'))
2014-01-09 14:04:22 -05:00
onThangBeganTalking: (e) ->
return unless @stage and @thang is e.thang
@stage?.startTalking()
onThangFinishedTalking: (e) ->
return unless @stage and @thang is e.thang
@stage?.stopTalking()
2014-01-03 13:32:13 -05:00
createProperties: ->
if @thang.id in ['Hero Placeholder', 'Hero Placeholder 1']
name = {knight: 'Tharin', captain: 'Anya', librarian: 'Hushbaum', sorcerer: 'Pender', 'potion-master': 'Omarn', samurai: 'Hattori', ninja: 'Amara'}[@thang.type] ? 'Hero'
else
name = if @thang.type then "#{@thang.id} - #{@thang.type}" else @thang.id
@$el.find('.thang-name').text name
props = @$el.find('.thang-props')
props.find('.prop').remove()
#propNames = _.without @thang.hudProperties ? [], 'action'
propNames = @thang.hudProperties
for prop, i in propNames
2014-01-03 13:32:13 -05:00
pel = @createPropElement prop
continue unless pel?
if pel.find('.bar').is('*') and props.find('.bar').is('*')
props.find('.bar-prop').last().after pel # Keep bars together
else
props.append pel
null
2014-01-03 13:32:13 -05:00
update: ->
return unless @thang
@$el.find('.thang-props-column').toggleClass 'nonexistent', not @thang.exists
if @thang.exists
@updatePropElement(prop, @thang[prop]) for prop in @thang.hudProperties ? []
2014-01-03 13:32:13 -05:00
createPropElement: (prop) ->
2014-06-30 22:16:26 -04:00
if prop in ['maxHealth']
2014-01-03 13:32:13 -05:00
return null # included in the bar
context =
prop: prop
2014-09-04 18:14:27 -04:00
hasIcon: prop in ['health', 'pos', 'target', 'collectedThangIDs', 'gold', 'bountyGold', 'visualRange', 'attackDamage', 'attackRange', 'maxSpeed', 'attackNearbyEnemyRange']
2014-06-30 22:16:26 -04:00
hasBar: prop in ['health']
2014-01-03 13:32:13 -05:00
$(prop_template(context))
updatePropElement: (prop, val) ->
pel = @$el.find '.thang-props *[name=' + prop + ']'
2014-06-30 22:16:26 -04:00
if prop in ['maxHealth']
return # Don't show maxes--they're built into bar labels.
2014-06-30 22:16:26 -04:00
if prop in ['health']
max = @thang['max' + prop.charAt(0).toUpperCase() + prop.slice(1)]
regen = @thang[prop + 'ReplenishRate']
2014-01-03 13:32:13 -05:00
percent = Math.round 100 * val / max
2014-06-30 22:16:26 -04:00
pel.find('.bar').css 'width', percent + '%'
labelText = prop + ': ' + @formatValue(prop, val) + ' / ' + @formatValue(prop, max)
2014-01-03 13:32:13 -05:00
if regen
2014-06-30 22:16:26 -04:00
labelText += ' (+' + @formatValue(prop, regen) + '/s)'
pel.find('.bar-prop-value').text(Math.round(max)) if max
2014-01-03 13:32:13 -05:00
else
s = @formatValue(prop, val)
labelText = "#{prop}: #{s}"
if prop is 'attackDamage'
cooldown = @thang.actions.attack.cooldown
dps = @thang.attackDamage / cooldown
labelText += " / #{cooldown.toFixed(2)}s (DPS: #{dps.toFixed(2)})"
2014-01-03 13:32:13 -05:00
pel.find('.prop-value').text s
pel.attr 'title', labelText
2014-01-03 13:32:13 -05:00
pel
formatValue: (prop, val) ->
2014-06-30 22:16:26 -04:00
if prop is 'target' and not val
val = @thang['targetPos']
2014-01-03 13:32:13 -05:00
val = null if val?.isZero()
2014-06-30 22:16:26 -04:00
if prop is 'rotation'
return (val * 180 / Math.PI).toFixed(0) + '˚'
if prop.search(/Range$/) isnt -1
return val + 'm'
2014-01-03 13:32:13 -05:00
if typeof val is 'number'
if Math.round(val) == val or prop is 'gold' then return val.toFixed(0) # int
2014-01-03 13:32:13 -05:00
if -10 < val < 10 then return val.toFixed(2)
if -100 < val < 100 then return val.toFixed(1)
return val.toFixed(0)
2014-06-30 22:16:26 -04:00
if val and typeof val is 'object'
2014-01-03 13:32:13 -05:00
if val.id
return val.id
else if val.x and val.y
2014-01-29 11:38:37 -05:00
return "x: #{val.x.toFixed(0)} y: #{val.y.toFixed(0)}"
#return "x: #{val.x.toFixed(0)} y: #{val.y.toFixed(0)}, z: #{val.z.toFixed(0)}" # Debugging: include z
2014-01-03 13:32:13 -05:00
else if not val?
2014-06-30 22:16:26 -04:00
return 'No ' + prop
2014-01-03 13:32:13 -05:00
return val
2014-01-09 14:04:22 -05:00
destroy: ->
@stage?.stopTalking()
super()