BattleSim/server/bw/battle_controller.coffee

129 lines
4.3 KiB
CoffeeScript

conditions = require '../conditions'
{_} = require 'underscore'
# Abstracts out sending messages from player to battle.
# Makes the Battle smoothly go into the next turn
# Necessary to separate out making commands and executing commands.
class @BattleController
constructor: (@battle) ->
conditions.attach(this)
@battle.emit('initialize')
BATTLE_DELEGATES = 'getPlayer isOver sendRequestTo
add remove'.trim().split(/\s+/)
for method in BATTLE_DELEGATES
do (method) =>
this::[method] = ->
@battle[method].apply(@battle, arguments)
# Returns all the player ids participating in this battle.
getPlayerIds: ->
@battle.playerIds
# Returns all the names of players participating in this battle.
# These names may be masked by alts
getPlayerNames: ->
@battle.playerNames
# Tells the player to execute a certain move by name. The move is added
# to the list of player actions, which are executed once the turn continues.
makeMove: (playerId, moveName, forSlot = 0, forTurn = @battle.turn, options = {}) ->
return false if @battle.isOver()
return false if forTurn != @battle.turn
return false if playerId not in @battle.playerIds
pokemon = @battle.getTeam(playerId).at(forSlot)
return false if !pokemon
request = @battle.requestFor(pokemon)
return false if !request
return false if moveName not in (request.moves || [])
move = @battle.getMove(moveName)
@battle.recordMove(playerId, move, forSlot, options)
@transitionToNextState()
return true
# Tells the player to switch with a certain pokemon specified by position.
# The switch is added to the list of player actions, which are executed
# once the turn continues.
makeSwitch: (playerId, toPosition, forSlot = 0, forTurn = @battle.turn) ->
return false if @battle.isOver()
return false if forTurn != @battle.turn
return false if playerId not in @battle.playerIds
pokemon = @battle.getTeam(playerId).at(forSlot)
return false if !pokemon
request = @battle.requestFor(pokemon)
return false if !request
return false if toPosition not in (request.switches || [])
@battle.recordSwitch(playerId, toPosition, forSlot)
@transitionToNextState()
return true
# Tells the player to cancel their latest completed request.
undoCompletedRequest: (playerId, forTurn = @battle.turn) ->
return false if forTurn != @battle.turn
@battle.undoCompletedRequest(playerId)
@sendUpdates()
return true
# Makes a player forfeit.
forfeit: (playerId) ->
return if @battle.isOver()
@battle.forfeit(playerId)
@sendUpdates()
messageSpectators: (user, message) ->
# In case the user is an alt.
userName = @battle.getPlayerName(user.name)
for spectator in @battle.spectators
spectator.send('updateBattleChat', @battle.id, userName, message)
rawMessage: (message) ->
for spectator in @battle.spectators
spectator.send('rawBattleMessage', @battle.id, message)
# Continue or begin a new turn if each player has made an action.
transitionToNextState: ->
return if not @battle.areAllRequestsCompleted()
if @battle.replacing
@battle.performReplacements()
@sendUpdates()
else
@continueTurn()
# Officially starts the battle.
beginBattle: ->
@battle.begin()
@sendUpdates()
beginTurn: ->
@battle.beginTurn()
@sendUpdates()
# Continues the turn. This is called once all requests
# have been submitted and the battle is ready to continue.
#
# If there are no more requests, the engine progresses to endTurn. Otherwise,
# it waits for continueTurn to be called again.
continueTurn: ->
@battle.continueTurn()
# If all requests have been completed, then end the turn.
# Otherwise, wait for further requests to be completed before ending.
if @battle.areAllRequestsCompleted() then @endTurn()
@sendUpdates()
# Calls Battle#endTurn. If all pokemon are fainted, then it
# ends the battle. Otherwise, it will request for new pokemon and wait if
# any replacements are needed, or begins the next turn.
endTurn: ->
@battle.endTurn()
@sendUpdates()
endBattle: ->
@battle.endBattle()
@sendUpdates()
# Sends battle updates to spectators.
sendUpdates: ->
@battle.sendUpdates()