# globals $table = null table_height = 0 card_height = 0 state = null server_url = null top_card_z = 0 # css z-index of front-most card piles = null window.log = [] show_message = (txt) -> window.log.push txt if window.log.length > 20 window.log.shift() return # timeout function with args in convenient order timeout = (ms, func) -> setTimeout func, ms unless Array::shuffle? Array::shuffle = -> return if @length is 0 top = @length while --top current = Math.floor(Math.random() * (top + 1)) tmp = @[current] @[current] = @[top] @[top] = tmp return new_button = (text) -> $ $ "
#{text}
" # transform coordinates from client-side coords to server-side coords (or back) # this makes it so p2 view everything upside down (mirrored), but still sends coords rightside up flip_y = (y) -> table_height - card_height - y transform_x = (x) -> x transform_y = (y) -> return y unless state.agent is 'p2' return flip_y y next_card_z = -> return top_card_z += 1 bring_card_to_front = (card) -> card.view.css "z-index": next_card_z() new_blank_card = (x, y) -> view = $ $ "
" $table.append view return view uninstantiate_card = (card) -> show_message "uninstantiate card #{card.number}" card.view.remove() delete card.view instantiate_card = (card) -> show_message "instantiate card #{card.number}" if card.view die.a.horrible.death() text = card.text if card.owner is state.agent card_class = 'my_card' else card_class = 'your_card' if card.z > top_card_z top_card_z = card.z view = $ $ "
#{text}
" card.view = view button_box = $ $ '
' flip_button = new_button "flip over" mark_button = new_button "mark" flip_button.bind 'click', -> state.flip state.agent, card.number, ! view.hasClass 'flipped' mark_button.bind 'click', -> state.mark state.agent, card.number, ! view.hasClass 'marked' button_box.append flip_button button_box.append mark_button view.append button_box if card.marked view.addClass 'marked' if card.flipped view.addClass 'flipped' $table.append view view.draggable containment: '#table', grid: [20, 20] view.bind 'dragstart', (event, ui) -> view.css 'z-index': card.z = next_card_z() if card.pile? delete card.pile update_pile_views() view.bind 'dragstop', (event, ui) -> p = view.position() pile = null # FIXME figure out what pile we moved to state.move state.agent, card.number, transform_x(p.left), transform_y(p.top), card.z, pile error_lag = 3 outgoing_messages = [] # message should be [agent, method, args...] # don't forget the agent (state.agent) tell_server = (message) -> outgoing_messages.push message send_updates() send_updates = -> return if outgoing_messages.length is 0 messages = outgoing_messages outgoing_messages = [] $.ajax "#{server_url}/set", { cache: false data: { agent: state.agent game: 'test' # FIXME, and in the /get call too messages: JSON.stringify(messages) } type: 'POST' dataType: 'json' error: (xhr, status, error) -> show_message "Network error while sending, you might want to refresh. Trying again in #{error_lag} seconds. (Status: #{status}, Error: #{error})" for message in messages outgoing_messages.unshift message timeout error_lag * 1000, send_updates error_lag *= 2 success: (data, status, xhr) -> show_message "update sent" error_lag = 3 } error_lag = 3 poll_for_updates = -> $.ajax "#{server_url}/get?agent=#{state.agent}&game=test", { cache: false type: 'GET' dataType: 'json' error: (xhr, status, error) -> show_message "Network error, you might want to refresh. Trying again in #{error_lag} seconds. (Status: #{status}, Error: #{error})" timeout error_lag * 1000, poll_for_updates error_lag *= 2 success: (data, status, xhr) -> state.process_messages data timeout 100, poll_for_updates error_lag = 3 } n_cards = (count) -> return "#{count} cards" unless count is 1 return "1 card" initialize_cards = () -> show_message 'initialize_cards' $('.card').remove() top_card_z = 0 # instantiate cards in play for card in state.cards delete card.view instantiate_card card unless card.pile? unless piles? piles = [ # global {key: 'p2_draw', x: transform_x(140), y: transform_y(20), name: "Draw Pile"} {key: 'p2_discard', x: transform_x(20), y: transform_y(20), name: "Discard Pile"} {key: 'p1_draw', x: transform_x(140), y: transform_y(flip_y(20)), name: "Draw Pile"} {key: 'p1_discard', x: transform_x(20), y: transform_y(flip_y(20)), name: "Discard Pile"} ] for pile in piles pile.$blank = new_blank_card pile.x, pile.y pile.$caption = $ $ "
#{pile.name}:
#{n_cards 0}
" update_pile_views() update_pile_views = -> ps = {} for card in state.cards if card.pile? if ps[card.pile]? ps[card.pile].total += 1 if card.z > ps[card.pile].top_z if ps[card.pile].top_card.view? uninstantiate_card ps[card.pile].top_card ps[card.pile].top_card = card ps[card.pile].top_z = card.z else ps[card.pile] = { total: 1, top_card: card, top_z: card.z } for pile in piles # where should the caption be? if ps[pile.key]? unless ps[pile.key].top_card.view? ps[pile.key].top_card.x = pile.x ps[pile.key].top_card.y = pile.y instantiate_card ps[pile.key].top_card caption_dest = ps[pile.key].top_card.view else caption_dest = pile.$blank if caption_dest isnt pile.caption_loc pile.$caption.detach() caption_dest.append pile.$caption pile.caption_loc = caption_dest # update caption to show correct number of cards in the pile card_count = 0 card_count = ps[pile.key].total if ps[pile.key]? pile.$caption.children('.n_cards').html n_cards card_count init = -> if window.location.hash? and window.location.hash.length > 0 me = window.location.hash.substr 1 winloc = "#{window.location}" server_url = winloc.substr 0, winloc.length - window.location.hash.length else me = 'p1' server_url = window.location state = window.game_model.new me state.on 'move', (agent, card, x, y, z, pile) -> update_pile_views() if agent is me tell_server ['move', agent, card, x, y, z, pile] else # FIXME should we use the z from the server? Should p1 use odd numbers and p2 even? bring_card_to_front state.cards[card] state.cards[card].view.animate { left: "#{transform_x x}px", top: "#{transform_y y}px"}, 800 state.on 'mark', (agent, card, state) -> @cards[card].view.toggleClass 'marked', state if agent is me tell_server ['mark', agent, card, state] state.on 'flip', (agent, card, state) -> @cards[card].view.toggleClass 'flipped', state if agent is me tell_server ['flip', agent, card, state] state.on 'set_cards', (agent, cards) -> initialize_cards() if agent is me tell_server ['set_cards', agent, cards] # timeout so browser will stop showing that we're loading timeout 1, poll_for_updates timeout 2, -> # ask for initial state tell_server ['send_state', state.agent] $ -> $table = $ '#table' table_height = $table.height() card_height = $('#loading-card').outerHeight() init()