Primitivus: Tarot card game implementation
- quick frontend: card_game added - wix: card_game splitted with quick frontend - tools: new game library - primitivus: new card_game widget (not finished yet) - primitivus: SàT XML UI management: first draft
This commit is contained in:
parent
451d574a8f
commit
3d5c5ada3c
9 changed files with 557 additions and 105 deletions
149
frontends/primitivus/card_game.py
Normal file
149
frontends/primitivus/card_game.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Primitivus: a SAT frontend
|
||||
Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import urwid
|
||||
from tools.games import TarotCard
|
||||
from quick_frontend.quick_card_game import QuickCardGame
|
||||
from xmlui import XMLUI
|
||||
|
||||
class Hand(urwid.WidgetWrap):
|
||||
"""Used to display several cards, and manage a hand"""
|
||||
|
||||
def __init__(self):
|
||||
self.columns = urwid.Columns([])
|
||||
urwid.WidgetWrap.__init__(self, self.columns)
|
||||
|
||||
def update(self, hand):
|
||||
"""Update the hand displayed in this widget"""
|
||||
del self.columns.widget_list[:]
|
||||
del self.columns.column_types[:]
|
||||
for card in hand:
|
||||
self.columns.widget_list.append(urwid.Text(card.getAttrText()))
|
||||
self.columns.column_types.append(('weight',1))
|
||||
|
||||
|
||||
|
||||
|
||||
class Card(TarotCard):
|
||||
"""This class is used to represent a card, logically
|
||||
and give a text representation with attributes"""
|
||||
|
||||
def __init__(self, suit, value):
|
||||
"""@param file: path of the PNG file"""
|
||||
TarotCard.__init__(self, (suit, value))
|
||||
|
||||
def getAttrText(self):
|
||||
"""return text representation of the card with attributes"""
|
||||
try:
|
||||
value = "%02i" % int(self.value)
|
||||
except ValueError:
|
||||
value = self.value[0].upper()+self.value[1]
|
||||
if self.suit == "atout":
|
||||
if self.value == "excuse":
|
||||
suit = 'c'
|
||||
else:
|
||||
suit = 'A'
|
||||
color = 'neutral'
|
||||
elif self.suit == "pique":
|
||||
suit = u'♠'
|
||||
color = 'black'
|
||||
elif self.suit == "trefle":
|
||||
suit = u'♣'
|
||||
color = 'black'
|
||||
elif self.suit == "coeur":
|
||||
suit = u'♥'
|
||||
color = 'red'
|
||||
elif self.suit == "carreau":
|
||||
suit = u'♦'
|
||||
color = 'red'
|
||||
if self.bout:
|
||||
color = 'special'
|
||||
return ('card_%s' % color,u"%s%s" % (value,suit))
|
||||
|
||||
class CardGame(QuickCardGame,urwid.WidgetWrap):
|
||||
"""Widget for card games"""
|
||||
|
||||
def __init__(self, parent, referee, players, player_nick):
|
||||
QuickCardGame.__init__(self, parent, referee, players, player_nick)
|
||||
self.loadCards()
|
||||
self.top = urwid.Pile([urwid.Padding(urwid.Text(self.top_nick), 'center')])
|
||||
self.top_card_wid = urwid.Text('')
|
||||
self.center_cards_wid = urwid.Text(' - ')
|
||||
self.bottom_card_wid = urwid.Text('')
|
||||
center = urwid.Pile([urwid.Padding(self.top_card_wid,'center'),
|
||||
urwid.Columns([('fixed',len(self.left_nick),urwid.Text(self.left_nick)),
|
||||
urwid.Padding(self.center_cards_wid,'center'),
|
||||
('fixed',len(self.right_nick),urwid.Text(self.right_nick))
|
||||
]),
|
||||
urwid.Padding(self.bottom_card_wid,'center')
|
||||
])
|
||||
body = urwid.Filler(center)
|
||||
self.hand_wid = Hand()
|
||||
self.main_frame = urwid.Frame(body,header=self.top, footer=self.hand_wid)
|
||||
urwid.WidgetWrap.__init__(self,self.main_frame)
|
||||
self.parent.host.bridge.tarotGameReady(player_nick, referee, profile_key = self.parent.host.profile)
|
||||
|
||||
def loadCards(self):
|
||||
"""Load all the cards in memory"""
|
||||
QuickCardGame.loadCards(self)
|
||||
for value in map(str,range(1,22))+['excuse']:
|
||||
card = Card('atout',value)
|
||||
self.cards[card.suit, card.value]=card
|
||||
self.deck.append(card)
|
||||
for suit in ["pique", "coeur", "carreau", "trefle"]:
|
||||
for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]:
|
||||
card = Card(suit,value)
|
||||
self.cards[card.suit, card.value]=card
|
||||
self.deck.append(card)
|
||||
|
||||
def newGame(self, hand):
|
||||
"""Start a new game, with given hand"""
|
||||
QuickCardGame.newGame(self, hand)
|
||||
self.hand_wid.update(self.hand)
|
||||
self.parent.host.redraw()
|
||||
|
||||
def contratSelected(self, data):
|
||||
"""Called when the contrat has been choosed
|
||||
@param data: form result"""
|
||||
contrat = data[0][1]
|
||||
QuickCardGame.contratSelected(self, contrat)
|
||||
|
||||
def chooseContrat(self, xml_data):
|
||||
"""Called when the player as to select his contrat
|
||||
@param xml_data: SàT xml representation of the form"""
|
||||
misc = {'callback': self.contratSelected}
|
||||
form = XMLUI(self.parent.host, xml_data, title = _('Please choose your contrat'), options = ['NO_CANCEL'], misc = misc)
|
||||
form.show()
|
||||
|
||||
"""def selectable(self):
|
||||
return True
|
||||
|
||||
def keypress(self, size, key):
|
||||
return key
|
||||
|
||||
def render(self, size, focus=False):
|
||||
return self.display_widget(size, focus).render(size, focus)
|
||||
|
||||
def display_widget(self, size, focus):
|
||||
(maxcol,maxrow) = size
|
||||
|
||||
return self.main_frame"""
|
||||
|
||||
|
|
@ -25,6 +25,7 @@ from quick_frontend.quick_chat import QuickChat
|
|||
import custom_widgets
|
||||
import time
|
||||
from tools.jid import JID
|
||||
from card_game import CardGame
|
||||
|
||||
|
||||
class ChatText(urwid.FlowWidget):
|
||||
|
|
@ -79,8 +80,10 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
self.content = urwid.SimpleListWalker([])
|
||||
self.text_list = urwid.ListBox(self.content)
|
||||
self.chat_widget = urwid.Frame(self.text_list)
|
||||
self.columns = urwid.Columns([('weight', 8, self.chat_widget)])
|
||||
urwid.WidgetWrap.__init__(self, self.__getDecoration(self.columns))
|
||||
self.chat_colums = urwid.Columns([('weight', 8, self.chat_widget)])
|
||||
self.chat_colums = urwid.Columns([('weight', 8, self.chat_widget)])
|
||||
self.pile = urwid.Pile([self.chat_colums])
|
||||
urwid.WidgetWrap.__init__(self, self.__getDecoration(self.pile))
|
||||
self.setType(type)
|
||||
self.day_change = time.strptime(time.strftime("%a %b %d 00:00:00 %Y")) #struct_time of day changing time
|
||||
self.show_timestamp = True
|
||||
|
|
@ -91,7 +94,7 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
def keypress(self, size, key):
|
||||
if key == "meta p": #user wants to (un)hide the presents panel
|
||||
if self.type == 'group':
|
||||
widgets = self.columns.widget_list
|
||||
widgets = self.chat_colums.widget_list
|
||||
if self.present_panel in widgets:
|
||||
self.__removePresentPanel()
|
||||
else:
|
||||
|
|
@ -135,7 +138,7 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
if type == 'one2one':
|
||||
self.historyPrint(profile=self.host.profile)
|
||||
elif type == 'group':
|
||||
if len(self.columns.widget_list) == 1:
|
||||
if len(self.chat_colums.widget_list) == 1:
|
||||
present_widget = self.__buildPresentList()
|
||||
self.present_panel = custom_widgets.VerticalSeparator(present_widget)
|
||||
self.__appendPresentPanel()
|
||||
|
|
@ -144,10 +147,11 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
return custom_widgets.LabelLine(widget, custom_widgets.SurroundedText(unicode(self.target)))
|
||||
|
||||
def showDecoration(self, show=True):
|
||||
"""Show/Hide the decoration around the chat window"""
|
||||
if show:
|
||||
main_widget = self.__getDecoration(self.columns)
|
||||
main_widget = self.__getDecoration(self.pile)
|
||||
else:
|
||||
main_widget = self.columns
|
||||
main_widget = self.pile
|
||||
self._w = main_widget
|
||||
|
||||
|
||||
|
|
@ -156,13 +160,28 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
return self.present_wid
|
||||
|
||||
def __appendPresentPanel(self):
|
||||
self.columns.widget_list.append(self.present_panel)
|
||||
self.columns.column_types.append(('weight', 2))
|
||||
self.chat_colums.widget_list.append(self.present_panel)
|
||||
self.chat_colums.column_types.append(('weight', 2))
|
||||
|
||||
def __removePresentPanel(self):
|
||||
self.columns.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.columns
|
||||
self.columns.widget_list.remove(self.present_panel)
|
||||
del self.columns.column_types[-1]
|
||||
self.chat_colums.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.chat_colums
|
||||
self.chat_colums.widget_list.remove(self.present_panel)
|
||||
del self.chat_colums.column_types[-1]
|
||||
|
||||
def __appendGamePanel(self, widget):
|
||||
assert (len(self.pile.widget_list) == 1)
|
||||
self.pile.widget_list.insert(0,widget)
|
||||
self.pile.item_types.insert(0,('weight', 1))
|
||||
self.pile.widget_list.insert(1,urwid.Filler(urwid.Divider('-')))
|
||||
self.pile.item_types.insert(1,('fixed', 1))
|
||||
self.host.redraw()
|
||||
|
||||
def __removeGamePanel(self):
|
||||
assert (len(self.pile.widget_list) == 3)
|
||||
self.pile.set_focus(0) #necessary as the focus change to the next object, we can go out of range if we are on the last object of self.chat_colums
|
||||
del self.pile.widget_list[0]
|
||||
del self.pile.item_types[0]
|
||||
self.host.redraw()
|
||||
|
||||
def setSubject(self, subject, wrap='space'):
|
||||
"""Set title for a group chat"""
|
||||
|
|
@ -209,11 +228,25 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
self.content.append(ChatText(self, timestamp or None, my_jid, from_jid, msg))
|
||||
self.text_list.set_focus(len(self.content)-1)
|
||||
self.host.redraw()
|
||||
|
||||
def startGame(self, game_type, referee, players):
|
||||
"""Configure the chat window to start a game"""
|
||||
if game_type=="Tarot":
|
||||
try:
|
||||
self.tarot_wid = CardGame(self, referee, players, self.nick)
|
||||
self.__appendGamePanel(self.tarot_wid)
|
||||
except e:
|
||||
self.host.debug()
|
||||
|
||||
def getGame(self, game_type):
|
||||
"""Return class managing the game type"""
|
||||
#TODO: check that the game is launched, and manage errors
|
||||
if game_type=="Tarot":
|
||||
return self.tarot_wid
|
||||
|
||||
#MENU EVENTS#
|
||||
def onTarotRequest(self, menu):
|
||||
if len(self.occupants) != 4:
|
||||
self.host.debug()
|
||||
self.host.showPopUp(custom_widgets.Alert(_("Can't start game"), _("You need to be exactly 4 peoples in the room to start a Tarot game"), ok_cb=self.host.removePopUp))
|
||||
else:
|
||||
self.host.bridge.tarotGameCreate(self.id, list(self.occupants), self.host.profile)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import urwid
|
|||
from urwid.escape import utf8decode
|
||||
|
||||
class Password(urwid.Edit):
|
||||
toto=0
|
||||
"""Edit box which doesn't show what is entered (show '*' or other char instead)"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -47,11 +46,6 @@ class Password(urwid.Edit):
|
|||
super(Password,self).insert_text(text)
|
||||
|
||||
def render(self, size, focus=False):
|
||||
Password.toto+=1
|
||||
if Password.toto==30:
|
||||
import os,pdb
|
||||
os.system('reset')
|
||||
pdb.set_trace()
|
||||
return super(Password, self).render(size, focus)
|
||||
|
||||
class AdvancedEdit(urwid.Edit):
|
||||
|
|
|
|||
|
|
@ -69,6 +69,14 @@ const_PALETTE = [('title', 'black', 'light gray', 'standout,underline'),
|
|||
('selected_menu', 'light gray,bold', 'dark green'),
|
||||
('menuitem', 'light gray,bold', 'dark red'),
|
||||
('menuitem_focus', 'light gray,bold', 'dark green'),
|
||||
('card_neutral', 'dark gray', 'white', 'standout,underline'),
|
||||
('card_neutral_selected', 'dark gray', 'dark green', 'standout,underline'),
|
||||
('card_special', 'brown', 'white', 'standout,underline'),
|
||||
('card_special_selected', 'brown', 'dark green', 'standout,underline'),
|
||||
('card_red', 'dark red', 'white', 'standout,underline'),
|
||||
('card_red_selected', 'dark red', 'dark green', 'standout,underline'),
|
||||
('card_black', 'black', 'white', 'standout,underline'),
|
||||
('card_black_selected', 'black', 'dark green', 'standout,underline'),
|
||||
]
|
||||
|
||||
class ChatList(QuickChatList):
|
||||
|
|
@ -205,7 +213,7 @@ class PrimitivusApp(QuickApp):
|
|||
if contact:
|
||||
assert(len(self.center_part.widget_list)==2)
|
||||
self.center_part.widget_list[1] = self.chat_wins[contact]
|
||||
self.menu_roller.addMenu(_('Chat Menu'), self.chat_wins[contact].getMenu())
|
||||
self.menu_roller.addMenu(_('Chat menu'), self.chat_wins[contact].getMenu())
|
||||
|
||||
def onTextEntered(self, editBar):
|
||||
"""Called when text is entered in the main edit bar"""
|
||||
|
|
|
|||
196
frontends/primitivus/xmlui.py
Normal file
196
frontends/primitivus/xmlui.py
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Primitivus: a SAT frontend
|
||||
Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import urwid
|
||||
import custom_widgets
|
||||
from xml.dom import minidom
|
||||
|
||||
class Pairs(urwid.WidgetWrap):
|
||||
|
||||
def __init__(self, weight_0='1', weight_1='1'):
|
||||
self.idx = 0
|
||||
self.weight_0 = weight_0
|
||||
self.weight_1 = weight_1
|
||||
columns = urwid.Columns([urwid.Text(''), urwid.Text('')])
|
||||
#XXX: empty Text hack needed because Pile doesn't support empty list
|
||||
urwid.WidgetWrap.__init__(self,columns)
|
||||
|
||||
def append(self, widget):
|
||||
pile = self._w.widget_list[self.idx]
|
||||
if pile.__class__ == urwid.Text:
|
||||
self._w.widget_list[self.idx] = urwid.Pile([widget])
|
||||
else:
|
||||
pile.widget_list.append(widget)
|
||||
pile.item_types.append(('weight',getattr(self,'weight_'+str(self.idx))))
|
||||
self.idx = (self.idx + 1) % 2
|
||||
|
||||
|
||||
class XMLUI(urwid.WidgetWrap):
|
||||
|
||||
def __init__(self, host, xml_data, title = None, options = [], misc={}):
|
||||
self.host = host
|
||||
self.title = title
|
||||
self.options = options
|
||||
self.misc = misc
|
||||
self.ctrl_list = {} # usefull to access ctrl
|
||||
widget = self.constructUI(xml_data)
|
||||
urwid.WidgetWrap.__init__(self,widget)
|
||||
|
||||
def __parseElems(self, node, parent):
|
||||
"""Parse elements inside a <layout> tags, and add them to the parent"""
|
||||
for elem in node.childNodes:
|
||||
if elem.nodeName != "elem":
|
||||
message=_("Unmanaged tag")
|
||||
error(message)
|
||||
raise Exception(message)
|
||||
id = elem.getAttribute("id")
|
||||
name = elem.getAttribute("name")
|
||||
type = elem.getAttribute("type")
|
||||
value = elem.getAttribute("value") if elem.hasAttribute('value') else u''
|
||||
if type=="empty":
|
||||
ctrl = urwid.Text('')
|
||||
elif type=="text":
|
||||
try:
|
||||
value = elem.childNodes[0].wholeText
|
||||
except KeyError:
|
||||
warning (_("text node has no child !"))
|
||||
ctrl = urwid.Text(value)
|
||||
elif type=="label":
|
||||
ctrl = urwid.Text(value+": ")
|
||||
elif type=="string":
|
||||
ctrl = urwid.Edit(edit_text = value)
|
||||
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
|
||||
elif type=="password":
|
||||
ctrl = custom_widgets.Password(edit_text = value)
|
||||
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
|
||||
elif type=="textbox":
|
||||
ctrl = urwid.Edit(edit_text = value, multiline=True)
|
||||
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
|
||||
elif type=="list":
|
||||
style=[] if elem.getAttribute("multi")=='yes' else ['single']
|
||||
ctrl = custom_widgets.List(options=[option.getAttribute("value") for option in elem.getElementsByTagName("option")], style=style)
|
||||
self.ctrl_list[name] = ({'type':type, 'control':ctrl})
|
||||
elif type=="button":
|
||||
callback_id = elem.getAttribute("callback_id")
|
||||
ctrl = urwid.Button(value, on_press=self.onButtonPress)
|
||||
ctrl.param_id = (callback_id,[field.getAttribute('name') for field in elem.getElementsByTagName("field_back")])
|
||||
else:
|
||||
error(_("FIXME FIXME FIXME: type [%s] is not implemented") % type) #FIXME !
|
||||
raise NotImplementedError
|
||||
parent.append(ctrl)
|
||||
|
||||
def __parseChilds(self, current, elem, wanted = ['layout']):
|
||||
"""Recursively parse childNodes of an elemen
|
||||
@param current: widget container with 'append' method
|
||||
@param elem: element from which childs will be parsed
|
||||
@param wanted: list of tag names that can be present in the childs to be SàT XMLUI compliant"""
|
||||
for node in elem.childNodes:
|
||||
if wanted and not node.nodeName in wanted:
|
||||
raise Exception("Invalid XMLUI") #TODO: make a custom exception
|
||||
if node.nodeName == "layout":
|
||||
type = node.getAttribute('type')
|
||||
if type == "tabs":
|
||||
raise NotImplementedError
|
||||
self.__parseChilds(current, None, node, ['category'])
|
||||
else:
|
||||
if type == "vertical":
|
||||
pass
|
||||
elif type == "pairs":
|
||||
pairs = Pairs()
|
||||
current.append(pairs)
|
||||
current = pairs
|
||||
else:
|
||||
warning(_("Unknown layout, using default one"))
|
||||
self.__parseElems(node, current)
|
||||
elif node.nodeName == "category":
|
||||
raise NotImplementedError
|
||||
"""name = node.getAttribute('name')
|
||||
if not node.nodeName in wanted or not name or not isinstance(parent,wx.Notebook):
|
||||
raise Exception("Invalid XMLUI") #TODO: make a custom exception
|
||||
notebook = parent
|
||||
tab_panel = wx.Panel(notebook, -1)
|
||||
tab_panel.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
tab_panel.SetSizer(tab_panel.sizer)
|
||||
notebook.AddPage(tab_panel, name)
|
||||
self.__parseChilds(tab_panel, None, node, ['layout'])"""
|
||||
|
||||
else:
|
||||
message=_("Unknown tag")
|
||||
error(message)
|
||||
raise Exception(message) #TODO: raise a custom exception here
|
||||
|
||||
def constructUI(self, xml_data):
|
||||
|
||||
list_box = urwid.ListBox(urwid.SimpleListWalker([]))
|
||||
|
||||
cat_dom = minidom.parseString(xml_data.encode('utf-8'))
|
||||
top= cat_dom.documentElement
|
||||
self.type = top.getAttribute("type")
|
||||
if not self.title:
|
||||
self.title = top.getAttribute("title") #TODO: manage title
|
||||
if top.nodeName != "sat_xmlui" or not self.type in ['form', 'param', 'window']:
|
||||
raise Exception("Invalid XMLUI") #TODO: make a custom exception
|
||||
|
||||
self.__parseChilds(list_box.body, cat_dom.documentElement)
|
||||
|
||||
if self.type == 'form':
|
||||
buttons = []
|
||||
buttons.append(urwid.Button(_('Submit'),self.onFormSubmitted))
|
||||
if not 'NO_CANCEL' in self.options:
|
||||
buttons.append(urwid.Button(_('Cancel'),self.onFormCancelled))
|
||||
max_len = max([len(button.get_label()) for button in buttons])
|
||||
grid_wid = urwid.GridFlow(buttons,max_len+4,1,0,'center')
|
||||
list_box.body.append(grid_wid)
|
||||
|
||||
|
||||
return list_box
|
||||
|
||||
def show(self):
|
||||
"""Show the constructed UI"""
|
||||
decorated = custom_widgets.LabelLine(self, custom_widgets.SurroundedText(self.title or ''))
|
||||
self.host.showPopUp(decorated)
|
||||
self.host.redraw()
|
||||
|
||||
|
||||
##EVENTS##
|
||||
|
||||
def onButtonPress(self, button):
|
||||
self.host.debug()
|
||||
|
||||
def onFormSubmitted(self, button):
|
||||
data = []
|
||||
for ctrl_name in self.ctrl_list:
|
||||
ctrl = self.ctrl_list[ctrl_name]
|
||||
if isinstance(ctrl['control'], custom_widgets.List):
|
||||
data.append((ctrl_name, ctrl['control'].getSelectedValue()))
|
||||
else:
|
||||
data.append((ctrl_name, ctrl['control'].get_edit_text()))
|
||||
if self.misc.has_key('action_back'): #FIXME FIXME FIXME: WTF ! Must be cleaned
|
||||
raise NotImplementedError
|
||||
self.host.debug()
|
||||
elif self.misc.has_key('callback'):
|
||||
self.misc['callback'](data)
|
||||
else:
|
||||
warning (_("The form data is not sent back, the type is not managed properly"))
|
||||
self.host.removePopUp()
|
||||
|
||||
def onFormCancelled(self, button):
|
||||
self.host.removePopUp()
|
||||
|
|
@ -297,7 +297,7 @@ class QuickApp():
|
|||
self.chat_wins[room_jid].getGame("Tarot").newGame(hand)
|
||||
|
||||
def tarotChooseContrat(self, room_jid, xml_data, profile):
|
||||
"""Called when the player has too select his contrat"""
|
||||
"""Called when the player has to select his contrat"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Tarot: need to select a contrat"))
|
||||
|
|
|
|||
131
frontends/quick_frontend/quick_card_game.py
Normal file
131
frontends/quick_frontend/quick_card_game.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
helper class for making a SAT frontend
|
||||
Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from logging import debug, info, error
|
||||
from tools.jid import JID
|
||||
|
||||
|
||||
|
||||
class QuickCardGame():
|
||||
|
||||
def __init__(self, parent, referee, players, player_nick):
|
||||
self.parent = parent
|
||||
self.referee = referee
|
||||
self.players = players
|
||||
self.played = {}
|
||||
for player in players:
|
||||
self.played[player] = None
|
||||
self.player_nick = player_nick
|
||||
self.bottom_nick = unicode(self.player_nick)
|
||||
idx = self.players.index(self.player_nick)
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.right_nick = unicode(self.players[idx])
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.top_nick = unicode(self.players[idx])
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.left_nick = unicode(self.players[idx])
|
||||
self.bottom_nick = unicode(player_nick)
|
||||
self.selected = [] #Card choosed by the player (e.g. during ecart)
|
||||
self.hand_size = 13 #number of cards in a hand
|
||||
self.hand = []
|
||||
self.to_show = []
|
||||
self.state = None
|
||||
|
||||
def loadCards(self):
|
||||
"""Load all the cards in memory
|
||||
@param dir: directory where the PNG files are"""
|
||||
self.cards={}
|
||||
self.deck=[]
|
||||
self.cards["atout"]={} #As Tarot is a french game, it's more handy & logical to keep french names
|
||||
self.cards["pique"]={} #spade
|
||||
self.cards["coeur"]={} #heart
|
||||
self.cards["carreau"]={} #diamond
|
||||
self.cards["trefle"]={} #club
|
||||
|
||||
def newGame(self, hand):
|
||||
"""Start a new game, with given hand"""
|
||||
assert (len(self.hand) == 0)
|
||||
for suit, value in hand:
|
||||
self.hand.append(self.cards[suit, value])
|
||||
self.hand.sort()
|
||||
self.state = "init"
|
||||
|
||||
def contratSelected(self, contrat):
|
||||
"""Called when the contrat has been choosed
|
||||
@param data: form result"""
|
||||
self.parent.host.bridge.tarotGameContratChoosed(self.player_nick, self.referee, contrat or 'Passe', self.parent.host.profile)
|
||||
|
||||
def chooseContrat(self, xml_data):
|
||||
"""Called when the player as to select his contrat
|
||||
@param xml_data: SàT xml representation of the form"""
|
||||
raise NotImplementedError
|
||||
|
||||
def showCards(self, game_stage, cards, data):
|
||||
"""Display cards in the middle of the game (to show for e.g. chien ou poignée)"""
|
||||
self.to_show = []
|
||||
for suit, value in cards:
|
||||
self.to_show.append(self.cards[suit, value])
|
||||
if game_stage == "chien" and data['attaquant'] == self.player_nick:
|
||||
self.state = "wait_for_ecart"
|
||||
else:
|
||||
self.state = "chien"
|
||||
|
||||
def MyTurn(self):
|
||||
"""Called when we have to play :)"""
|
||||
if self.state == "chien":
|
||||
self.to_show = []
|
||||
self.state = "play"
|
||||
|
||||
def showScores(self, xml_data, winners, loosers):
|
||||
"""Called when the player as to select hist contrat
|
||||
@param xml_data: SàT xml representation of the form"""
|
||||
raise NotImplementedError
|
||||
|
||||
def cardsPlayed(self, player, cards):
|
||||
"""A card has been played by player"""
|
||||
if self.to_show:
|
||||
self.to_show = []
|
||||
pl_cards = []
|
||||
if self.played[player] != None: #gof: à supprimer
|
||||
for pl in self.played:
|
||||
self.played[pl] = None
|
||||
for suit, value in cards:
|
||||
pl_cards.append(self.cards[suit, value])
|
||||
self.played[player] = pl_cards[0]
|
||||
|
||||
def invalidCards(self, phase, played_cards, invalid_cards):
|
||||
"""Invalid cards have been played
|
||||
@param phase: phase of the game
|
||||
@param played_cards: all the cards played
|
||||
@param invalid_cards: cards which are invalid"""
|
||||
|
||||
if phase == "play":
|
||||
self.state = "play"
|
||||
elif phase == "ecart":
|
||||
self.state = "ecart"
|
||||
else:
|
||||
error ('INTERNAL ERROR: unmanaged game phase')
|
||||
|
||||
for suit, value in played_cards:
|
||||
self.hand.append(self.cards[suit, value])
|
||||
|
||||
self.hand.sort()
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from logging import debug, info, error
|
||||
from logging import debug, info, warning, error
|
||||
from tools.jid import JID
|
||||
|
||||
|
||||
|
|
@ -92,3 +92,12 @@ class QuickChat():
|
|||
"""Print message in chat window. Must be implemented by child class"""
|
||||
raise NotImplementedError
|
||||
|
||||
def startGame(self, game_type, referee, players):
|
||||
"""Configure the chat window to start a game"""
|
||||
#No need to raise an error as game are not mandatory
|
||||
warning(_('startGame is not implemented in this frontend'))
|
||||
|
||||
def getGame(self, game_type):
|
||||
"""Return class managing the game type"""
|
||||
#No need to raise an error as game are not mandatory
|
||||
warning(_('getGame is not implemented in this frontend'))
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import pdb
|
|||
from logging import debug, info, error
|
||||
from tools.jid import JID
|
||||
from tools.games import TarotCard
|
||||
from quick_frontend.quick_card_game import QuickCardGame
|
||||
from xmlui import XMLUI
|
||||
|
||||
CARD_WIDTH = 74
|
||||
|
|
@ -34,16 +35,16 @@ CARD_HEIGHT = 136
|
|||
MIN_WIDTH = 950 #Minimum size of the panel
|
||||
MIN_HEIGHT = 500
|
||||
|
||||
class wxCard(TarotCard):
|
||||
class WxCard(TarotCard):
|
||||
"""This class is used to represent a card, graphically and logically"""
|
||||
|
||||
def __init__(self, file):
|
||||
"""@param file: path of the PNG file"""
|
||||
self.bitmap = wx.Image(file).ConvertToBitmap()
|
||||
root_name = os.path.splitext(os.path.basename(file))[0]
|
||||
self.suit,self.value=root_name.split('_')
|
||||
TarotCard.__init__(self, (self.suit, self.value))
|
||||
print "Carte:",self.suit, self.value #, self.bout
|
||||
suit,value = root_name.split('_')
|
||||
TarotCard.__init__(self, (suit, value))
|
||||
print "Carte:",suit, value #, self.bout
|
||||
|
||||
def draw(self, dc, x, y):
|
||||
"""Draw the card on the device context
|
||||
|
|
@ -53,32 +54,15 @@ class wxCard(TarotCard):
|
|||
dc.DrawBitmap(self.bitmap, x, y, True)
|
||||
|
||||
|
||||
class CardPanel(wx.Panel):
|
||||
class CardPanel(QuickCardGame,wx.Panel):
|
||||
"""This class is used to display the cards"""
|
||||
|
||||
def __init__(self, parent, referee, players, player_nick):
|
||||
QuickCardGame.__init__(self, parent, referee, players, player_nick)
|
||||
wx.Panel.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.referee = referee
|
||||
self.players = players
|
||||
self.played = {}
|
||||
for player in players:
|
||||
self.played[player] = None
|
||||
self.player_nick = player_nick
|
||||
self.bottom_nick = self.player_nick
|
||||
idx = self.players.index(self.player_nick)
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.right_nick = self.players[idx]
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.top_nick = self.players[idx]
|
||||
idx = (idx + 1) % len(self.players)
|
||||
self.left_nick = self.players[idx]
|
||||
self.bottom_nick = player_nick
|
||||
self.SetMinSize(wx.Size(MIN_WIDTH, MIN_HEIGHT))
|
||||
self.load_cards("/home/goffi/dev/divers/images/cards/")
|
||||
self.loadCards("/home/goffi/dev/divers/images/cards/")
|
||||
self.mouse_over_card = None #contain the card to highlight
|
||||
self.selected = [] #Card choosed by the player (e.g. during ecart)
|
||||
self.hand_size = 13 #number of cards in a hand
|
||||
self.visible_size = CARD_WIDTH/2 #number of pixels visible for cards
|
||||
self.hand = []
|
||||
self.to_show = []
|
||||
|
|
@ -90,33 +74,18 @@ class CardPanel(wx.Panel):
|
|||
self.Bind(wx.EVT_LEFT_UP, self.onMouseClick)
|
||||
self.parent.host.bridge.tarotGameReady(player_nick, referee, profile_key = self.parent.host.profile)
|
||||
|
||||
def load_cards(self, dir):
|
||||
def loadCards(self, dir):
|
||||
"""Load all the cards in memory
|
||||
@param dir: directory where the PNG files are"""
|
||||
self.cards={}
|
||||
self.deck=[]
|
||||
self.cards["atout"]={} #As Tarot is a french game, it's more handy & logical to keep french names
|
||||
self.cards["pique"]={} #spade
|
||||
self.cards["coeur"]={} #heart
|
||||
self.cards["carreau"]={} #diamond
|
||||
self.cards["trefle"]={} #club
|
||||
QuickCardGame.loadCards(self)
|
||||
for file in glob.glob(dir+'/*_*.png'):
|
||||
card = wxCard(file)
|
||||
card = WxCard(file)
|
||||
self.cards[card.suit, card.value]=card
|
||||
self.deck.append(card)
|
||||
"""for value in map(str,range(1,22))+['excuse']:
|
||||
self.idx_cards.append(self.cards["atout",value])
|
||||
for suit in ["pique", "coeur", "carreau", "trefle"]:
|
||||
for value in map(str,range(1,11))+["valet","cavalier","dame","roi"]:
|
||||
self.idx_cards.append(self.cards[suit, value])""" #XXX: no need to sort the cards !
|
||||
|
||||
def newGame(self, hand):
|
||||
"""Start a new game, with given hand"""
|
||||
assert (len(self.hand) == 0)
|
||||
for suit, value in hand:
|
||||
self.hand.append(self.cards[suit, value])
|
||||
self.hand.sort()
|
||||
self.state = "init"
|
||||
QuickCardGame.newGame(self, hand)
|
||||
self._recalc_ori()
|
||||
self.Refresh()
|
||||
|
||||
|
|
@ -125,30 +94,14 @@ class CardPanel(wx.Panel):
|
|||
@param data: form result"""
|
||||
debug (_("Contrat choosed"))
|
||||
contrat = data[0][1]
|
||||
self.parent.host.bridge.tarotGameContratChoosed(self.player_nick, self.referee, contrat or 'Passe', self.parent.host.profile)
|
||||
QuickCardGame.contratSelected(self, contrat)
|
||||
|
||||
def chooseContrat(self, xml_data):
|
||||
"""Called when the player as to select hist contrat
|
||||
"""Called when the player as to select his contrat
|
||||
@param xml_data: SàT xml representation of the form"""
|
||||
misc = {'callback': self.contratSelected}
|
||||
form = XMLUI(self.parent.host, xml_data, title = _('Please choose your contrat'), options = ['NO_CANCEL'], misc = misc)
|
||||
|
||||
def showCards(self, game_stage, cards, data):
|
||||
"""Display cards in the middle of the game (to show for e.g. chien ou poignée)"""
|
||||
self.to_show = []
|
||||
for suit, value in cards:
|
||||
self.to_show.append(self.cards[suit, value])
|
||||
if game_stage == "chien" and data['attaquant'] == self.player_nick:
|
||||
self.state = "wait_for_ecart"
|
||||
else:
|
||||
self.state = "chien"
|
||||
|
||||
def MyTurn(self):
|
||||
"""Called when we have to play :)"""
|
||||
if self.state == "chien":
|
||||
self.to_show = []
|
||||
self.state = "play"
|
||||
|
||||
def showScores(self, xml_data, winners, loosers):
|
||||
"""Called when the player as to select hist contrat
|
||||
@param xml_data: SàT xml representation of the form"""
|
||||
|
|
@ -156,15 +109,7 @@ class CardPanel(wx.Panel):
|
|||
|
||||
def cardsPlayed(self, player, cards):
|
||||
"""A card has been played by player"""
|
||||
if self.to_show:
|
||||
self.to_show = []
|
||||
pl_cards = []
|
||||
if self.played[player] != None: #gof: à supprimer
|
||||
for pl in self.played:
|
||||
self.played[pl] = None
|
||||
for suit, value in cards:
|
||||
pl_cards.append(self.cards[suit, value])
|
||||
self.played[player] = pl_cards[0]
|
||||
QuickCardGame.cardsPlayed(self, player, cards)
|
||||
self.Refresh()
|
||||
|
||||
def invalidCards(self, phase, played_cards, invalid_cards):
|
||||
|
|
@ -172,25 +117,12 @@ class CardPanel(wx.Panel):
|
|||
@param phase: phase of the game
|
||||
@param played_cards: all the cards played
|
||||
@param invalid_cards: cards which are invalid"""
|
||||
QuickCardGame.invalidCards(self, phase, played_cards, invalid_cards)
|
||||
|
||||
if phase == "play":
|
||||
self.state = "play"
|
||||
elif phase == "ecart":
|
||||
self.state = "ecart"
|
||||
else:
|
||||
error ('INTERNAL ERROR: unmanaged game phase')
|
||||
|
||||
for suit, value in played_cards:
|
||||
self.hand.append(self.cards[suit, value])
|
||||
|
||||
self._recalc_ori()
|
||||
self.Refresh()
|
||||
self.hand.sort()
|
||||
wx.MessageDialog(self, _("Cards played are invalid !"), _("Error"), wx.OK | wx.ICON_ERROR).ShowModal()
|
||||
|
||||
|
||||
|
||||
|
||||
def _is_on_hand(self, pos_x, pos_y):
|
||||
"""Return True if the coordinate are on the hand cards"""
|
||||
if pos_x > self.orig_x and pos_y > self.orig_y \
|
||||
|
|
|
|||
Loading…
Reference in a new issue