2014-01-03 10:32:13 -08:00
CocoClass = require ' lib/CocoClass '
{ createProgressBar } = require ' ./sprite_utils '
Camera = require ' ./Camera '
Mark = require ' ./Mark '
Label = require ' ./Label '
AudioPlayer = require ' lib/AudioPlayer '
2014-02-11 12:02:27 -08:00
{ me } = require ' lib/auth '
2014-01-03 10:32:13 -08:00
# We'll get rid of this once level's teams actually have colors
healthColors =
ogres: [ 64 , 128 , 212 ]
humans: [ 255 , 0 , 0 ]
neutral: [ 64 , 212 , 128 ]
# Sprite: EaselJS-based view/controller for Thang model
module.exports = CocoSprite = class CocoSprite extends CocoClass
thangType: null # ThangType instance
displayObject: null
imageObject: null
healthBar: null
marks: null
labels: null
options:
resolutionFactor: 4
groundLayer: null
textLayer: null
floatingLayer: null
frameRateFactor: 1 # TODO: use or lose?
thang: null
camera: null
spriteSheetCache: null
showInvisible: false
flipped: false
flippedCount: 0
originalScaleX: null
originalScaleY: null
actionQueue: null
actions: null
rotation: 0
# ACTION STATE
# Actions have relations. If you say 'move', 'move_side' may play because of a direction
# relationship, and if you say 'cast', 'cast_begin' may happen first, or 'cast_end' after.
currentRootAction: null # action that, in general, is playing or will play
currentAction: null # related action that is right now playing
subscriptions:
' level-sprite-dialogue ' : ' onDialogue '
' level-sprite-clear-dialogue ' : ' onClearDialogue '
' level-set-letterbox ' : ' onSetLetterbox '
2014-01-05 01:05:03 -05:00
' surface:ticked ' : ' onSurfaceTicked '
2014-01-03 10:32:13 -08:00
constructor: (@thangType, options) ->
2014-01-30 16:36:36 -08:00
super ( )
2014-01-03 10:32:13 -08:00
@options = _ . extend ( _ . cloneDeep ( @ options ) , options )
@ setThang @ options . thang
console . error @ toString ( ) , " has no ThangType! " unless @ thangType
@actionQueue = [ ]
@marks = { }
@labels = { }
2014-03-12 13:49:36 -07:00
@handledAoEs = { }
2014-01-31 10:21:32 -08:00
@age = 0
2014-01-20 17:20:04 -08:00
@displayObject = new createjs . Container ( )
if @ thangType . get ( ' actions ' )
2014-02-24 12:52:35 -08:00
@ setupSprite ( )
2014-01-20 17:20:04 -08:00
else
@stillLoading = true
@ thangType . fetch ( )
2014-02-24 12:52:35 -08:00
@ thangType . once ' sync ' , @ setupSprite , @
2014-01-30 16:36:36 -08:00
2014-02-24 12:52:35 -08:00
setupSprite: ->
2014-01-20 17:20:04 -08:00
@stillLoading = false
2014-01-03 10:32:13 -08:00
@actions = @ thangType . getActions ( )
@ buildFromSpriteSheet @ buildSpriteSheet ( )
destroy: ->
mark . destroy ( ) for name , mark of @ marks
label . destroy ( ) for name , label of @ labels
2014-02-12 12:41:41 -08:00
@ imageObject ? . off ' animationend ' , @ playNextAction
@playNextAction = null
@ displayObject ? . off ( )
2014-03-06 15:52:09 -08:00
clearInterval @ effectInterval if @ effectInterval
2014-02-14 10:57:47 -08:00
super ( )
2014-01-03 10:32:13 -08:00
toString: -> " <CocoSprite: #{ @ thang ? . id } > "
2014-01-14 13:16:30 -08:00
buildSpriteSheet: ->
2014-02-17 17:38:49 -08:00
options = _ . extend @ options , @ thang ? . getSpriteOptions ? ( ) ? { }
2014-01-15 15:16:31 -08:00
options.colorConfig = @ options . colorConfig if @ options . colorConfig
2014-01-14 13:16:30 -08:00
options.async = false
@ thangType . getSpriteSheet options
2014-01-03 10:32:13 -08:00
buildFromSpriteSheet: (spriteSheet) ->
if spriteSheet
sprite = new createjs . Sprite ( spriteSheet )
else
sprite = new createjs . Shape ( )
sprite.scaleX = sprite.scaleY = 1 / @ options . resolutionFactor
2014-01-06 15:36:35 -08:00
# temp, until these are re-exported with perspective
2014-01-30 16:36:36 -08:00
if @ options . camera and @ thangType . get ( ' name ' ) in [ ' Dungeon Floor ' , ' Indoor Floor ' , ' Grass ' , ' Goal Trigger ' , ' Obstacle ' ]
2014-01-03 10:32:13 -08:00
sprite . scaleY *= @ options . camera . y2x
2014-02-24 12:52:35 -08:00
@ displayObject . removeChild ( @ imageObject ) if @ imageObject
2014-01-03 10:32:13 -08:00
@imageObject = sprite
@ displayObject . addChild ( sprite )
@ addHealthBar ( )
@ configureMouse ( )
# TODO: generalize this later?
@originalScaleX = sprite . scaleX
@originalScaleY = sprite . scaleY
@displayObject.sprite = @
@displayObject.layerPriority = @ thangType . get ' layerPriority '
@displayObject.name = @ thang ? . spriteName or @ thangType . get ' name '
2014-02-12 12:41:41 -08:00
@ imageObject . on ' animationend ' , @ playNextAction
2014-01-03 10:32:13 -08:00
##################################################
# QUEUEING AND PLAYING ACTIONS
queueAction: (action) ->
# The normal way to have an action play
action = @ actions [ action ] if _ . isString ( action )
action ? = @ actions . idle
@actionQueue = [ ]
@ actionQueue . push @ currentRootAction . relatedActions . end if @ currentRootAction ? . relatedActions ? . end
@ actionQueue . push action . relatedActions . begin if action . relatedActions ? . begin
@ actionQueue . push action
2014-02-06 17:00:02 -08:00
if action . goesTo and nextAction = @ actions [ action . goesTo ]
@ actionQueue . push nextAction if nextAction
2014-01-03 10:32:13 -08:00
@currentRootAction = action
@ playNextAction ( )
2014-01-31 10:21:32 -08:00
onSurfaceTicked: (e) -> @ age += e . dt
2014-01-03 10:32:13 -08:00
2014-02-12 12:41:41 -08:00
playNextAction: =>
2014-01-03 10:32:13 -08:00
@ playAction ( @ actionQueue . splice ( 0 , 1 ) [ 0 ] ) if @ actionQueue . length
playAction: (action) ->
@currentAction = action
2014-02-05 14:57:05 -08:00
return @ hide ( ) unless action . animation or action . container or action . relatedActions
@ show ( )
2014-01-03 10:32:13 -08:00
return @ updateActionDirection ( ) unless action . animation or action . container
m = if action . container then " gotoAndStop " else " gotoAndPlay "
@imageObject.framerate = action . framerate or 20
2014-02-17 11:53:52 -08:00
@ imageObject [ m ] action . name
2014-01-03 10:32:13 -08:00
reg = @ getOffset ' registration '
@imageObject.regX = - reg . x
@imageObject.regY = - reg . y
2014-01-09 11:04:22 -08:00
if @ currentRootAction . name is ' move ' and action . frames
2014-01-03 10:32:13 -08:00
start = Math . floor ( Math . random ( ) * action . frames . length )
@imageObject.currentAnimationFrame = start
2014-02-05 14:57:05 -08:00
hide: ->
@hiding = true
@ updateAlpha ( )
2014-02-11 09:28:26 -08:00
2014-02-05 14:57:05 -08:00
show: ->
@hiding = false
@ updateAlpha ( )
2014-02-24 16:42:34 -08:00
2014-02-24 14:40:28 -08:00
stop: ->
@ imageObject ? . stop ? ( )
mark . stop ( ) for name , mark of @ marks
2014-02-24 16:42:34 -08:00
2014-02-24 14:40:28 -08:00
play: ->
@ imageObject ? . play ? ( )
mark . play ( ) for name , mark of @ marks
2014-02-05 14:57:05 -08:00
2014-03-12 09:10:36 -07:00
update: (frameChanged) ->
2014-01-03 10:32:13 -08:00
# Gets the sprite to reflect what the current state of the thangs and surface are
2014-01-20 17:20:04 -08:00
return if @ stillLoading
2014-01-03 10:32:13 -08:00
@ updatePosition ( )
2014-03-12 09:31:45 -07:00
if frameChanged
2014-03-12 12:43:51 -07:00
@ updateScale ( ) # must happen before rotation
2014-03-12 09:31:45 -07:00
@ updateAlpha ( )
@ updateRotation ( )
@ updateAction ( )
@ updateStats ( )
@ updateGold ( )
2014-03-12 13:49:36 -07:00
@ showAreaOfEffects ( )
2014-01-03 10:32:13 -08:00
@ updateMarks ( )
@ updateLabels ( )
2014-03-12 13:49:36 -07:00
showAreaOfEffects: ->
return unless @ thang ? . currentEvents
for event in @ thang . currentEvents
continue unless event . startsWith ' aoe- '
continue if @ handledAoEs [ event ]
@ handledAoEs [ event ] = true
args = JSON . parse ( event [ 4 . . . ] )
pos = @ options . camera . worldToSurface { x : args [ 0 ] , y : args [ 1 ] }
circle = new createjs . Shape ( )
circle . graphics . beginFill ( args [ 3 ] ) . drawCircle ( 0 , 0 , args [ 2 ] * Camera . PPM )
circle.x = pos . x
circle.y = pos . y
circle.scaleY = @ options . camera . y2x * 0.7
circle.scaleX = 0.7
circle.alpha = 0.2
circle
@ options . groundLayer . addChild circle
createjs . Tween . get ( circle )
. to ( { alpha: 0.6 , scaleY: @ options . camera . y2x , scaleX: 1 } , 100 , createjs . Ease . circOut )
. to ( { alpha: 0 , scaleY: 0 , scaleX: 0 } , 700 , createjs . Ease . circIn )
. call =>
2014-03-14 17:15:07 -07:00
return if @ destroyed
2014-03-12 13:49:36 -07:00
@ options . groundLayer . removeChild circle
delete @ handledAoEs [ event ]
2014-01-03 10:32:13 -08:00
cache: ->
bounds = @ imageObject . getBounds ( )
@ displayObject . cache 0 , 0 , bounds . width , bounds . height
#console.log "just cached", @thang.id, "which was at", @imageObject.x, @imageObject.y, bounds.width, bounds.height, "with scale", Math.max(@imageObject.scaleX, @imageObject.scaleY)
2014-01-31 10:21:32 -08:00
getBobOffset: ->
return 0 unless @ thang . bobHeight
@ thang . bobHeight * ( 1 + Math . sin ( @ age * Math . PI / @ thang . bobTime ) )
2014-03-05 19:39:14 -08:00
getWorldPosition: ->
p1 = @ thang . pos
if bobOffset = @ getBobOffset ( )
p1 = p1 . copy ? ( ) or _ . clone ( p1 )
p1 . z += bobOffset
x: p1 . x , y: p1 . y , z: if @ thang . isLand then 0 else p1 . z - @ thang . depth / 2
2014-01-03 10:32:13 -08:00
updatePosition: ->
return unless @ thang ? . pos and @ options . camera ?
2014-03-05 19:54:58 -08:00
wop = @ getWorldPosition ( )
2014-01-03 10:32:13 -08:00
[ p0 , p1 ] = [ @ lastPos , @ thang . pos ]
return if p0 and p0 . x is p1 . x and p0 . y is p1 . y and p0 . z is p1 . z and not @ options . camera . tweeningZoomTo
sup = @ options . camera . worldToSurface wop
[ @ displayObject . x , @ displayObject . y ] = [ sup . x , sup . y ]
2014-01-31 10:21:32 -08:00
@lastPos = p1 . copy ? ( ) or _ . clone ( p1 )
2014-01-05 01:05:03 -05:00
@hasMoved = true
2014-01-03 10:32:13 -08:00
updateScale: ->
if @ thangType . get ( ' matchWorldDimensions ' ) and @ thang
if @ thang . width isnt @ lastThangWidth or @ thang . height isnt @ lastThangHeight
[ @ lastThangWidth , @ lastThangHeight ] = [ @ thang . width , @ thang . height ]
bounds = @ imageObject . getBounds ( )
2014-02-24 16:42:34 -08:00
@imageObject.scaleX = @ thang . width * Camera . PPM / bounds . width
@imageObject.scaleY = @ thang . height * Camera . PPM * @ options . camera . y2x / bounds . height
unless @ thang . spriteName is ' Beam '
@ imageObject . scaleX *= @ thangType . get ( ' scale ' ) ? 1
@ imageObject . scaleY *= @ thangType . get ( ' scale ' ) ? 1
2014-01-03 10:32:13 -08:00
return
scaleX = if @ getActionProp ' flipX ' then - 1 else 1
scaleY = if @ getActionProp ' flipY ' then - 1 else 1
scaleFactor = @ thang . scaleFactor ? 1
2014-02-06 08:27:49 -08:00
scaleFactorX = @ thang . scaleFactorX ? scaleFactor
scaleFactorY = @ thang . scaleFactorY ? scaleFactor
@imageObject.scaleX = @ originalScaleX * scaleX * scaleFactorX
@imageObject.scaleY = @ originalScaleY * scaleY * scaleFactorY
2014-01-03 10:32:13 -08:00
updateAlpha: ->
2014-02-05 14:57:05 -08:00
@imageObject.alpha = if @ hiding then 0 else 1
2014-01-03 10:32:13 -08:00
return unless @ thang ? . alpha ?
@imageObject.alpha = @ thang . alpha
if @ options . showInvisible
2014-01-05 01:05:03 -05:00
@imageObject.alpha = Math . max 0.5 , @ imageObject . alpha
2014-01-03 10:32:13 -08:00
updateRotation: (imageObject) ->
rotationType = @ thangType . get ( ' rotationType ' )
return if rotationType is ' fixed '
rotation = @ getRotation ( )
imageObject ? = @ imageObject
return imageObject.rotation = rotation if not rotationType
@ updateIsometricRotation ( rotation , imageObject )
getRotation: ->
return @ rotation if not @ thang ? . rotation
rotation = @ thang ? . rotation
rotation = ( 360 - ( rotation * 180 / Math . PI ) % 360 ) % 360
rotation -= 360 if rotation > 180
rotation
updateIsometricRotation: (rotation, imageObject) ->
2014-01-23 20:08:35 -08:00
return unless @ currentAction
return if _ . string . endsWith ( @ currentAction . name , ' back ' )
return if _ . string . endsWith ( @ currentAction . name , ' fore ' )
2014-03-12 09:31:45 -07:00
imageObject . scaleX *= - 1 if Math . abs ( rotation ) >= 90
2014-01-03 10:32:13 -08:00
##################################################
updateAction: ->
action = @ determineAction ( )
2014-03-15 11:31:12 -07:00
isDifferent = action isnt @ currentRootAction or action is null
2014-03-05 12:53:11 -08:00
if not action and @ thang ? . actionActivated and not @ stopLogging
console . error " action is " , action , " for " , @ thang ? . id , " from " , @ currentRootAction , @ thang . action , @ thang . getActionName ? ( )
@stopLogging = true
2014-01-03 10:32:13 -08:00
@ queueAction ( action ) if isDifferent or ( @ thang ? . actionActivated and action . name isnt ' move ' )
@ updateActionDirection ( )
determineAction: ->
action = null
action = @ thang . getActionName ( ) if @ thang ? . acts
action ? = @ currentRootAction . name if @ currentRootAction ?
action ? = ' idle '
action = null unless @ actions [ action ] ?
return null unless action
action = ' break ' if @ actions . break ? and @ thang ? . erroredOut
action = ' die ' if @ actions . die ? and @ thang ? . health ? and @ thang . health <= 0
@ actions [ action ]
updateActionDirection: (@wallGrid=null) ->
# wallGrid is only needed for wall grid face updates; should refactor if this works
return unless action = @ getActionDirection ( )
@ playAction ( action ) if action isnt @ currentAction
getActionDirection: (rootAction=null) ->
rootAction ? = @ currentRootAction
return null unless relatedActions = rootAction ? . relatedActions ? { }
rotation = @ getRotation ( )
if relatedActions [ " 111111111111 " ] # has grid-surrounding-wall-based actions
if @ wallGrid
action = ' '
tileSize = 4
[ gx , gy ] = [ @ thang . pos . x , @ thang . pos . y ]
for y in [ gy + tileSize , gy , gy - tileSize , gy - tileSize * 2 ]
for x in [ gx - tileSize , gx , gx + tileSize ]
if x >= 0 and y >= 0 and x < @ wallGrid . width and y < @ wallGrid . height
wallThangs = @ wallGrid . contents x , y
else
wallThangs = [ ' outside of the map yo ' ]
if wallThangs . length is 0
if y is gy and x is gx
action += " 1 " # the center wall we're placing
else
action += " 0 "
else if wallThangs . length is 1
action += " 1 "
else
console . error " Overlapping walls at " , x , y , " ... " , wallThangs
action += " 1 "
matchedAction = ' 111111111111 '
for relatedAction of relatedActions
if action . match ( relatedAction . replace ( /\?/g , ' . ' ) )
matchedAction = relatedAction
break
#console.log "returning", matchedAction, "for", @thang.id, "at", gx, gy
return relatedActions [ matchedAction ]
else
keys = _ . keys relatedActions
index = Math . max 0 , Math . floor ( ( 179 + rotation ) / 360 * keys . length )
#console.log "Showing", relatedActions[keys[index]]
return relatedActions [ keys [ index ] ]
value = Math . abs ( rotation )
direction = null
direction = ' side ' if value <= 45 or value >= 135
direction = ' fore ' if 135 > rotation > 45
direction = ' back ' if - 135 < rotation < - 45
relatedActions [ direction ]
updateStats: ->
if bar = @ healthBar
return if @ thang . health is @ lastHealth
@lastHealth = @ thang . health
healthPct = Math . max ( @ thang . health / @ thang . maxHealth , 0 )
2014-03-07 17:37:11 -08:00
bar.scaleX = healthPct / bar . baseScale
2014-01-03 10:32:13 -08:00
healthOffset = @ getOffset ' aboveHead '
[ bar . x , bar . y ] = [ healthOffset . x - bar . width / 2 , healthOffset . y ]
configureMouse: ->
@displayObject.cursor = ' pointer ' if @ thang ? . isSelectable
@displayObject.mouseEnabled = @displayObject.mouseChildren = false unless @ thang ? . isSelectable or @ thang ? . isLand
if @ displayObject . mouseEnabled
@ displayObject . on ' mousedown ' , @ onMouseEvent , @ , false , ' sprite:mouse-down '
@ displayObject . on ' click ' , @ onMouseEvent , @ , false , ' sprite:clicked '
@ displayObject . on ' dblclick ' , @ onMouseEvent , @ , false , ' sprite:double-clicked '
@ displayObject . on ' pressmove ' , @ onMouseEvent , @ , false , ' sprite:dragged '
@ displayObject . on ' pressup ' , @ onMouseEvent , @ , false , ' sprite:mouse-up '
onSetLetterbox: (e) ->
@letterboxOn = e . on
onMouseEvent: (e, ourEventName) ->
return if @ letterboxOn
Backbone . Mediator . publish ourEventName , sprite: @ , thang: @ thang , originalEvent: e
addHealthBar: ->
@ displayObject . removeChild @ healthBar if @ healthBar ? . parent
return unless @ thang ? . health ? and " health " in ( @ thang ? . hudProperties ? [ ] )
healthColor = healthColors [ @ thang ? . team ] ? healthColors [ " neutral " ]
healthOffset = @ getOffset ' aboveHead '
bar = @healthBar = createProgressBar ( healthColor , healthOffset . y )
bar.x = healthOffset . x - bar . width / 2
bar.name = ' health bar '
2014-03-07 17:37:11 -08:00
bar . cache 0 , - bar . height * bar . baseScale / 2 , bar . width * bar . baseScale , bar . height * bar . baseScale
2014-01-03 10:32:13 -08:00
@ displayObject . addChild bar
getActionProp: (prop, subProp, def=null) ->
# Get a property or sub-property from an action, falling back to ThangType
for val in [ @ currentAction ? [ prop ] , @ thangType . get ( prop ) ]
val = val [ subProp ] if val ? and subProp
return val if val ?
def
getOffset: (prop) ->
# Get the proper offset from either the current action or the ThangType
def = x: 0 , y: { registration: 0 , torso: - 50 , mouth: - 60 , aboveHead: - 100 } [ prop ]
pos = @ getActionProp ' positions ' , prop , def
pos = x: pos . x , y: pos . y
scale = @ getActionProp ' scale ' , null , 1
scale *= @ options . resolutionFactor if prop is ' registration '
pos . x *= scale
pos . y *= scale
2014-03-06 17:21:24 -08:00
if @ thang and prop isnt ' registration '
2014-03-06 15:52:09 -08:00
scaleFactor = @ thang . scaleFactor ? 1
pos . x *= @ thang . scaleFactorX ? scaleFactor
pos . y *= @ thang . scaleFactorY ? scaleFactor
2014-01-03 10:32:13 -08:00
pos
updateMarks: ->
return unless @ options . camera
2014-03-06 15:52:09 -08:00
@ addMark ' repair ' , null , ' repair ' if @ thang ? . errorsOut
2014-01-03 10:32:13 -08:00
@ marks . repair ? . toggle @ thang ? . errorsOut
@ addMark ( ' bounds ' ) . toggle true if @ thang ? . drawsBounds
@ addMark ( ' shadow ' ) . toggle true unless @ thangType . get ( ' shadow ' ) is 0
mark . update ( ) for name , mark of @ marks
2014-03-07 21:02:10 -08:00
#@thang.effectNames = ['berserk', 'confuse', 'control', 'curse', 'fear', 'poison', 'paralyze', 'regen', 'sleep', 'slow', 'haste']
2014-03-06 17:13:16 -08:00
@ updateEffectMarks ( ) if @ thang ? . effectNames ? . length or @ previousEffectNames ? . length
2014-03-06 16:32:13 -08:00
2014-03-06 15:52:09 -08:00
updateEffectMarks: ->
return if _ . isEqual @ thang . effectNames , @ previousEffectNames
for effect in @ thang . effectNames
mark = @ addMark effect , @ options . floatingLayer , effect
mark.statusEffect = true
mark . toggle ' on '
mark . show ( )
2014-03-06 16:32:13 -08:00
2014-03-06 15:52:09 -08:00
if @ previousEffectNames
for effect in @ previousEffectNames
2014-03-12 09:15:37 -07:00
continue if effect in @ thang . effectNames
2014-03-06 15:52:09 -08:00
mark = @ marks [ effect ]
2014-03-06 17:13:16 -08:00
mark . toggle false
2014-03-06 16:32:13 -08:00
2014-03-06 15:52:09 -08:00
if @ thang . effectNames . length > 1 and not @ effectInterval
@ rotateEffect ( )
@effectInterval = setInterval @ rotateEffect , 1500
2014-03-06 16:32:13 -08:00
2014-03-06 15:52:09 -08:00
else if @ effectInterval and @ thang . effectNames . length <= 1
2014-03-06 17:25:40 -08:00
clearInterval @ effectInterval
2014-03-06 15:52:09 -08:00
@effectInterval = null
2014-03-06 16:32:13 -08:00
2014-03-06 15:52:09 -08:00
@previousEffectNames = @ thang . effectNames
rotateEffect: =>
effects = ( m . name for m in _ . values ( @ marks ) when m . on and m . statusEffect and m . mark )
2014-03-06 17:25:40 -08:00
return unless effects . length
2014-03-06 15:52:09 -08:00
effects . sort ( )
@ effectIndex ? = 0
@effectIndex = ( @ effectIndex + 1 ) % effects . length
@ marks [ effect ] . hide ( ) for effect in effects
@ marks [ effects [ @ effectIndex ] ] . show ( )
2014-01-03 10:32:13 -08:00
setHighlight: (to, delay) ->
2014-03-06 15:52:09 -08:00
@ addMark ' highlight ' , @ options . floatingLayer , ' highlight ' if to
2014-01-03 10:32:13 -08:00
@ marks . highlight ? . highlightDelay = delay
@ marks . highlight ? . toggle to and not @ dimmed
setDimmed: (@dimmed) ->
@ marks . highlight ? . toggle @ marks . highlight . on and not @ dimmed
setThang: (@thang) ->
@options.thang = @ thang
setDebug: (debug) ->
return unless @ thang ? . collides and @ options . camera ?
@ addMark ' debug ' , @ options . floatingLayer if debug
@ marks . debug ? . toggle debug
getAverageDimension: ->
bounds = @ imageObject . getBounds ( )
averageDimension = ( bounds . height + bounds . width ) / 2
Math . min ( 80 , averageDimension )
addLabel: (name, style) ->
@ labels [ name ] ? = new Label sprite: @ , camera: @ options . camera , layer: @ options . textLayer , style: style
@ labels [ name ]
addMark: (name, layer, thangType=null) ->
@ marks [ name ] ? = new Mark name: name , sprite: @ , camera: @ options . camera , layer: layer ? @ options . groundLayer , thangType: thangType
@ marks [ name ]
notifySpeechUpdated: (e) ->
e = _ . clone ( e )
e.sprite = @
e . blurb ? = ' ... '
2014-01-09 11:04:22 -08:00
e.thang = @ thang
2014-01-03 10:32:13 -08:00
Backbone . Mediator . publish ' sprite:speech-updated ' , e
isTalking: ->
Boolean @ labels . dialogue ? . text or @ labels . say ? . text
onDialogue: (e) ->
return unless @ thang ? . id is e . spriteID
label = @ addLabel ' dialogue ' , Label . STYLE_DIALOGUE
label . setText e . blurb or ' ... '
sound = e . sound ? AudioPlayer . soundForDialogue e . message , @ thangType . get ' soundTriggers '
@ instance ? . stop ( )
if @instance = @ playSound sound , false
2014-02-12 12:41:41 -08:00
@ instance . addEventListener " complete " , -> Backbone . Mediator . publish ' dialogue-sound-completed '
2014-01-03 10:32:13 -08:00
@ notifySpeechUpdated e
onClearDialogue: (e) ->
@ labels . dialogue ? . setText null
@ instance ? . stop ( )
@ notifySpeechUpdated { }
setNameLabel: (name) ->
label = @ addLabel ' name ' , Label . STYLE_NAME
label . setText name
updateLabels: ->
return unless @ thang
blurb = if @ thang . health <= 0 then null else @ thang . sayMessage # Dead men tell no tales
@ addLabel ' say ' , Label . STYLE_SAY if blurb
if @ labels . say ? . setText blurb
@ notifySpeechUpdated blurb: blurb
label . update ( ) for name , label of @ labels
2014-02-11 12:02:27 -08:00
updateGold: ->
# TODO: eventually this should be moved into some sort of team-based update
# rather than an each-thang-that-shows-gold-per-team thing.
return if @ thang . gold is @ lastGold
gold = Math . floor @ thang . gold
return if gold is @ lastGold
@lastGold = gold
Backbone . Mediator . publish ' surface:gold-changed ' , { team: @ thang . team , gold: gold }
2014-01-03 10:32:13 -08:00
playSounds: (withDelay=true, volume=1.0) ->
for event in @ thang . currentEvents ? [ ]
@ playSound event , withDelay , volume
2014-02-11 12:02:27 -08:00
if event is ' pay-bounty-gold ' and @ thang . bountyGold > 25 and @ thang . team isnt me . team
2014-02-11 09:28:26 -08:00
AudioPlayer . playInterfaceSound ' coin_1 ' , 0.25
2014-01-03 10:32:13 -08:00
if @ thang . actionActivated and ( action = @ thang . getActionName ( ) ) isnt ' say '
@ playSound action , withDelay , volume
if @ thang . sayMessage and withDelay # don't play sayMessages while scrubbing, annoying
offsetFrames = Math . abs ( @ thang . sayStartTime - @ thang . world . age ) / @ thang . world . dt
if offsetFrames <= 2 # or (not withDelay and offsetFrames < 30)
sound = AudioPlayer . soundForDialogue @ thang . sayMessage , @ thangType . get ' soundTriggers '
@ playSound sound , false , volume
playSound: (sound, withDelay=true, volume=1.0) ->
if _ . isString sound
sound = @ thangType . get ( ' soundTriggers ' ) ? [ sound ]
if _ . isArray sound
sound = sound [ Math . floor Math . random ( ) * sound . length ]
return null unless sound
delay = if withDelay and sound . delay then 1000 * sound . delay / createjs . Ticker . getFPS ( ) else 0
name = AudioPlayer . nameForSoundReference sound
2014-03-05 19:39:14 -08:00
instance = AudioPlayer . playSound name , volume , delay , @ getWorldPosition ( )
2014-01-09 11:04:22 -08:00
# console.log @thang?.id, "played sound", name, "with delay", delay, "volume", volume, "and got sound instance", instance
2014-01-30 16:36:36 -08:00
instance