Firs commit
35
.gitignore
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
## Editors:
|
||||
*.bak
|
||||
*.sav
|
||||
*.backup
|
||||
.*.swp
|
||||
*~
|
||||
|
||||
# Secret configuration
|
||||
settings.cfg
|
||||
|
||||
# Personal conf
|
||||
static/jquery.js
|
||||
static/socket.io.js
|
||||
templates/head-perso.html
|
||||
templates/scripts-perso.html
|
373
belote.py
Normal file
@ -0,0 +1,373 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import flask
|
||||
from flask_socketio import SocketIO
|
||||
import flask_login as fll
|
||||
import datetime
|
||||
from db import db, User, Game, Player, levels_users
|
||||
from belote_jeu import N_TURN, N_PLAYERS
|
||||
import belote_ws
|
||||
|
||||
login_manager = fll.LoginManager()
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.config.from_pyfile('settings.cfg')
|
||||
|
||||
#######################################################################
|
||||
# Plugin management #
|
||||
#######################################################################
|
||||
|
||||
# SocketIO
|
||||
socketio = SocketIO(app)
|
||||
login_manager.init_app(app)
|
||||
|
||||
# Database management
|
||||
db.app = app
|
||||
db.init_app(app)
|
||||
db.create_all()
|
||||
db.session.commit()
|
||||
|
||||
# Insert admin if not exist
|
||||
if User.query.limit(1).first() is None:
|
||||
admin = User(login='admin', name='Admin', level=levels_users['Admin'])
|
||||
admin.set_password('admin')
|
||||
db.session.add(admin)
|
||||
db.session.commit()
|
||||
|
||||
for i in range(4):
|
||||
if User.query.get('leo'+str(i)) is None:
|
||||
leo = User(login='leo'+str(i), name='Leo '+str(i), level=levels_users['Can manage simple users'])
|
||||
leo.set_password('leo')
|
||||
db.session.add(leo)
|
||||
db.session.commit()
|
||||
|
||||
# Login management
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
if user_id is None :
|
||||
return None
|
||||
return User.query.get(user_id)
|
||||
|
||||
@login_manager.unauthorized_handler
|
||||
def unauthorized_callback():
|
||||
return flask.redirect('/login?next=' + flask.request.path)
|
||||
|
||||
|
||||
#######################################################################
|
||||
# Global variables or fuctions #
|
||||
#######################################################################
|
||||
URL_DEFAULT = '/games'
|
||||
namespaces_join = {}
|
||||
namespaces = {}
|
||||
|
||||
def create_namespace(gid, join=False):
|
||||
if(join):
|
||||
namespace = belote_ws.CustomNamespaceJoin(gid)
|
||||
namespaces_join[gid] = True
|
||||
socketio.on_namespace(namespace)
|
||||
else:
|
||||
namespace = belote_ws.CustomNamespacePlay(gid)
|
||||
namespaces[gid] = True
|
||||
socketio.on_namespace(namespace)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
user = fll.current_user
|
||||
if not hasattr(user, 'level'):
|
||||
user = None
|
||||
return flask.render_template("index.html", user=user)
|
||||
#######################################################################
|
||||
# Login, logout #
|
||||
#######################################################################
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if fll.current_user:
|
||||
flask.redirect(URL_DEFAULT)
|
||||
if flask.request.method=="POST":
|
||||
username = flask.request.form['username']
|
||||
password = flask.request.form['password']
|
||||
user = User.query.get(username)
|
||||
if user and user.level > levels_users['Inactive'] and user.check_password(password):
|
||||
fll.login_user(user)
|
||||
user.last_login = datetime.datetime.utcnow()
|
||||
next = flask.request.args.get('next')
|
||||
if next is not None and next[0]=='/':
|
||||
return flask.redirect(next)
|
||||
else:
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
else:
|
||||
app.logger.warning('Login fail for user {} from {}'.format(user, flask.request.remote_addr))
|
||||
flask.flash('Invalid username/password combination')
|
||||
return flask.render_template('login.html', user=None)
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
fll.logout_user()
|
||||
return flask.redirect('/')
|
||||
|
||||
#######################################################################
|
||||
# Games : list #
|
||||
#######################################################################
|
||||
|
||||
@app.route('/games')
|
||||
@fll.login_required
|
||||
def games():
|
||||
games = Game.query.all()
|
||||
mesjeux = []
|
||||
joinable = []
|
||||
for g in games:
|
||||
if g.admin==fll.current_user.login:
|
||||
mesjeux.append(g)
|
||||
elif g.can_join(fll.current_user):
|
||||
joinable.append(g)
|
||||
cancreategames = fll.current_user.level >= levels_users['Can create games']
|
||||
candeletegames = fll.current_user.level >= levels_users['Admin']
|
||||
return flask.render_template('games.html', mesjeux=mesjeux, joinable=joinable, user=fll.current_user, \
|
||||
cancreategames=cancreategames, candeletegames=candeletegames)
|
||||
|
||||
#######################################################################
|
||||
# Create, join and play to a game #
|
||||
#######################################################################
|
||||
|
||||
@app.route('/add_game', methods=['GET', 'POST'])
|
||||
@fll.login_required
|
||||
def game_add():
|
||||
player = fll.current_user
|
||||
if fll.current_user.level >= levels_users['Can create games']:
|
||||
if flask.request.method=="POST":
|
||||
name = flask.request.form['name']
|
||||
if name is None or name == '':
|
||||
return flask.redirect('/add_game')
|
||||
game = Game(name=name, admin=player.login)
|
||||
db.session.add(game)
|
||||
db.session.commit()
|
||||
game.join(fll.current_user)
|
||||
db.session.commit()
|
||||
return flask.redirect('/game/{}'.format(game.id))
|
||||
return flask.render_template('game_add.html', user=fll.current_user)
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
@app.route('/game/<roomid>/join')
|
||||
@fll.login_required
|
||||
def game_page_join(roomid):
|
||||
game = Game.query.get(roomid)
|
||||
if game:
|
||||
player = fll.current_user
|
||||
if game.start:
|
||||
return flask.redirect('/game/{}'.format(roomid))
|
||||
if game.can_join(player):
|
||||
if game.id not in namespaces_join:
|
||||
create_namespace(game.id, join=True)
|
||||
return flask.render_template('game_join.html', game=game, user=player, admin=game.admin)
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
@app.route('/game/<roomid>/start')
|
||||
@fll.login_required
|
||||
def game_page_start(roomid):
|
||||
game = Game.query.get(roomid)
|
||||
if game:
|
||||
player = fll.current_user
|
||||
if game.isadmin(player) and game.fixplayers and not game.start:
|
||||
return flask.render_template('game_start.html', game=game, user=player)
|
||||
return flask.redirect('/game/{}'.format(roomid))
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
@app.route('/game/<roomid>')
|
||||
@fll.login_required
|
||||
def game_page(roomid):
|
||||
game = Game.query.get(roomid)
|
||||
if game:
|
||||
player = fll.current_user
|
||||
if not game.start:
|
||||
return flask.redirect('/game/{}/join'.format(roomid))
|
||||
if game.authorized(player) :
|
||||
if game.id not in namespaces:
|
||||
create_namespace(game.id)
|
||||
return flask.render_template('game.html', game=game, user=player)
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
@app.route('/game/<roomid>/del')
|
||||
@fll.login_required
|
||||
def delgame(roomid):
|
||||
game = Game.query.get(roomid)
|
||||
if game is not None and fll.current_user.login == game.admin:
|
||||
confirm = flask.request.args.get('confirm')
|
||||
if confirm is not None:
|
||||
db.session.delete(game)
|
||||
db.session.commit()
|
||||
else:
|
||||
return flask.render_template('game_del.html', game=game, user=fll.current_user)
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
#######################################################################
|
||||
# Users management #
|
||||
#######################################################################
|
||||
@app.route('/admin/users')
|
||||
@fll.login_required
|
||||
def admin_users():
|
||||
if fll.current_user.level < levels_users['Can manage simple users']:
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
users = User.query.all()
|
||||
return flask.render_template('admin_users.html', user=fll.current_user, users=users)
|
||||
|
||||
@app.route('/admin/users/<user>', methods=['GET', 'POST'])
|
||||
@fll.login_required
|
||||
def edituser(user):
|
||||
new = user=='new'
|
||||
user = User.query.get(user)
|
||||
if not new and user is None:
|
||||
return flask.redirect('/admin/users')
|
||||
if fll.current_user.level >= levels_users['Admin'] or \
|
||||
fll.current_user.level >= levels_users['Can manage simple users'] and \
|
||||
fll.current_user.level > user.level:
|
||||
if flask.request.method=="POST":
|
||||
username = flask.request.form['username']
|
||||
name = flask.request.form['name']
|
||||
password = flask.request.form['password']
|
||||
level = int(flask.request.form['level'])
|
||||
if level not in levels_users.values():
|
||||
flask.flash('Level unknown')
|
||||
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
||||
if fll.current_user.level < levels_users['Admin']:
|
||||
if not level < fll.current_user.level:
|
||||
flask.flash('Invalid level')
|
||||
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
||||
if len(password)<2 and new:
|
||||
flask.flash('Mot de passe trop court')
|
||||
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
||||
if new and User.query.get(username) is not None:
|
||||
flask.flash('Login déjà utilisé ! Choisissez un autre !')
|
||||
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
||||
if new:
|
||||
usertoadd = User(login=username, name=name, level=level)
|
||||
usertoadd.set_password(password)
|
||||
db.session.add(usertoadd)
|
||||
else:
|
||||
user.name = name
|
||||
if len(password)>=2:
|
||||
user.password = password
|
||||
user.level = level
|
||||
db.session.commit()
|
||||
return flask.redirect('/admin/users')
|
||||
else:
|
||||
return flask.render_template("admin_user_edit.html", user=fll.current_user, useredit=user, levels_users=levels_users)
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
@app.route('/admin/users/<user>/del')
|
||||
@fll.login_required
|
||||
def deluser(user):
|
||||
user = User.query.get(user)
|
||||
if user is None:
|
||||
return flask.redirect('/admin/users')
|
||||
if fll.current_user.level >= levels_users['Admin'] or \
|
||||
fll.current_user.level >= levels_users['Can manage simple users'] and \
|
||||
fll.current_user.level > user.level:
|
||||
confirm = flask.request.args.get('confirm')
|
||||
if confirm is not None:
|
||||
delete_game(user=user)
|
||||
db.session.delete(user)
|
||||
db.session.commit()
|
||||
return flask.redirect('/admin/users')
|
||||
return flask.render_template("admin_user_del.html", user=fll.current_user, useredit=user)
|
||||
|
||||
@app.route('/password', methods=['GET', 'POST'])
|
||||
@fll.login_required
|
||||
def change_password():
|
||||
if flask.request.method=="POST":
|
||||
password = flask.request.form['password']
|
||||
if len(password) < 5:
|
||||
flask.flash('Mot de passe trop court !')
|
||||
else:
|
||||
fll.current_user.set_password(password)
|
||||
db.session.commit()
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
return flask.render_template("password.html", user=fll.current_user)
|
||||
|
||||
#######################################################################
|
||||
# Game managament #
|
||||
#######################################################################
|
||||
@app.route('/admin/games')
|
||||
@fll.login_required
|
||||
def admin_games():
|
||||
if fll.current_user.level < levels_users['Can manage games']:
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
games = Game.query.all()
|
||||
return flask.render_template('admin_games.html', user=fll.current_user, games=games)
|
||||
|
||||
@app.route('/admin/games/<roomid>/del')
|
||||
@fll.login_required
|
||||
def admin_game_del(roomid):
|
||||
game = Game.query.get(roomid)
|
||||
if game is None:
|
||||
return flask.redirect('/admin/games')
|
||||
if fll.current_user.level >= levels_users['Can manage games']:
|
||||
confirm = flask.request.args.get('confirm')
|
||||
if confirm is not None:
|
||||
delete_game(game=game)
|
||||
return flask.redirect('/admin/games')
|
||||
else:
|
||||
return flask.render_template('game_del.html', user=fll.current_user, game=game)
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
@app.route('/game/<roomid>/see')
|
||||
@fll.login_required
|
||||
def see_game(roomid):
|
||||
game = Game.query.get(roomid)
|
||||
if game is None:
|
||||
return flask.redirect('/games')
|
||||
if fll.current_user.level >= levels_users['Can manage games'] or game.authorized(fll.current_user) and game.turn==N_TURN*N_PLAYERS:
|
||||
return game.serialize_state_anonymous()
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
|
||||
@app.route('/admin/games/new', methods=['GET', 'POST'])
|
||||
@fll.login_required
|
||||
def admin_games_new():
|
||||
if fll.current_user.level < levels_users['Can manage games']:
|
||||
return flask.redirect(URL_DEFAULT)
|
||||
if flask.request.method=="POST":
|
||||
name = flask.request.form['name']
|
||||
admin = flask.request.form['admin']
|
||||
admin = User.query.get(admin)
|
||||
if admin is None:
|
||||
flask.flash('Login inconnu')
|
||||
elif len(name)<2:
|
||||
flask.flash('Nom trop court !')
|
||||
else:
|
||||
game = Game(name=name, admin=admin.login)
|
||||
db.session.add(game)
|
||||
db.session.commit()
|
||||
game.join(admin)
|
||||
db.session.commit()
|
||||
return flask.redirect('/admin/games')
|
||||
return flask.render_template('admin_game_add.html', user=fll.current_user)
|
||||
|
||||
|
||||
|
||||
def delete_game(user=None, game=None):
|
||||
if user is not None:
|
||||
games = Game.query.filter_by(admin=user.login).all()
|
||||
for g in games:
|
||||
for p in g.players:
|
||||
db.session.delete(p)
|
||||
db.session.delete(g)
|
||||
db.session.commit()
|
||||
if isinstance(game, int):
|
||||
g = Game.query.get(game)
|
||||
if g is not None:
|
||||
for p in g.players:
|
||||
db.session.delete(p)
|
||||
db.session.delete(g)
|
||||
db.session.commit()
|
||||
elif game is not None:
|
||||
for p in game.players:
|
||||
db.session.delete(p)
|
||||
db.session.delete(game)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
socketio.run(app, debug=True, host='0.0.0.0')
|
||||
|
8
belote.wsgi
Normal file
@ -0,0 +1,8 @@
|
||||
import os
|
||||
import sys
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
sys.path.insert(0,os.path.dirname(__file__)+'/venv/lib/python{}.{}/site-packages'.format(sys.version_info.major, sys.version_info.minor))
|
||||
sys.path.insert(0,os.path.dirname(__file__))
|
||||
|
||||
from belote import app as application
|
||||
|
148
belote_jeu.py
Normal file
@ -0,0 +1,148 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
N_PLAYERS = 4
|
||||
N_TURN = int(32/4)
|
||||
|
||||
# P : pique, C : Coeur, F : Carreau, T : Trèfle
|
||||
# 7..9, 0 puis VDRA
|
||||
cards =['AP', 'RP', 'DP', 'VP', '0P', '9P', '8P', '7P',
|
||||
'AC', 'RC', 'DC', 'VC', '0C', '9C', '8C', '7C',
|
||||
'AF', 'RF', 'DF', 'VF', '0F', '9F', '8F', '7F',
|
||||
'AT', 'RT', 'DT', 'VT', '0T', '9T', '8T', '7T'
|
||||
]
|
||||
|
||||
points_atout = {'V' : 20, '9' : 14, 'A': 11, '0': 10, 'R': 4, 'D': 3, '8':0, '7':0}
|
||||
points_atout_order = {'V' : 20, '9' : 14, 'A': 11, '0': 10, 'R': 4, 'D': 3, '8':1, '7':0}
|
||||
points_order = {'A': 11, '0': 10, 'R': 4, 'D': 3, 'V': 2, '9': 1, '8':0.5, '7':0}
|
||||
points = {'A': 11, '0': 10, 'R': 4, 'D': 3, 'V': 2, '9': 0, '8':0, '7':0}
|
||||
|
||||
translate = {'A': 'As', 'R' : 'Roi', 'D': 'Dame', 'V': 'Valet', '0': '10', 'P': 'Pique', 'C': 'Coeur', 'T':'Trèfle', 'F':'Carreau'}
|
||||
|
||||
colors = ['P', 'C', 'F', 'T']
|
||||
|
||||
def translator(card):
|
||||
s = []
|
||||
for c in card:
|
||||
if c in translate:
|
||||
s.append(translate[c])
|
||||
else:
|
||||
s.append(c)
|
||||
return ' '.join(s)
|
||||
|
||||
def winner(cards, atout):
|
||||
"""
|
||||
Returns id winner (0-3), number of points
|
||||
"""
|
||||
if isinstance(cards, str):
|
||||
cardsl = cards.split(',')
|
||||
cardss = cards
|
||||
else:
|
||||
cardss = ''.join(cards)
|
||||
cardsl = cards
|
||||
|
||||
if len(cardss)==0:
|
||||
return 0, 0
|
||||
winner = None
|
||||
if atout in cardss:
|
||||
for i in range(len(cardsl)):
|
||||
if cardsl[i][1] == atout:
|
||||
if winner is None or points_atout_order[cardsl[i][0]] > points_atout_order[cardsl[winner][0]]:
|
||||
winner = i
|
||||
if winner is None:
|
||||
couldemandee = cardss[1]
|
||||
for i in range(len(cardsl)):
|
||||
if cardsl[i][1] == couldemandee:
|
||||
if winner is None or points_order[cardsl[i][0]] > points_order[cardsl[winner][0]]:
|
||||
winner = i
|
||||
|
||||
pointsr = 0
|
||||
for c in cardsl:
|
||||
if c[1] == atout:
|
||||
pointsr += points_atout[c[0]]
|
||||
else:
|
||||
pointsr += points[c[0]]
|
||||
|
||||
return winner, pointsr
|
||||
|
||||
def legal_play(played, atout, card, main):
|
||||
if card not in cards:
|
||||
return False
|
||||
if card not in main:
|
||||
return False
|
||||
|
||||
if played is None :
|
||||
playedl = []
|
||||
playeds = ''
|
||||
elif isinstance(played, str):
|
||||
playedl = played.split(',')
|
||||
playeds = played
|
||||
else:
|
||||
playeds = ''.join(played)
|
||||
playedl = played
|
||||
|
||||
if main is None or main=='':
|
||||
main = []
|
||||
if isinstance(main, str):
|
||||
mains = main
|
||||
main = main.split(',')
|
||||
else:
|
||||
mains = ','.join(main)
|
||||
|
||||
# Le premier a jouer fait ce qu'il veut
|
||||
if len(playeds)==0:
|
||||
return True
|
||||
couldemandee =playeds[1]
|
||||
|
||||
# On regarde les atouts pour plus tard:
|
||||
maxpose = -1
|
||||
for c in playedl:
|
||||
if c[1]==atout and points_atout_order[c[0]]>maxpose:
|
||||
maxpose = points_atout_order[c[0]]
|
||||
|
||||
peutmonter = False
|
||||
has_atout = False
|
||||
for m in main: #Peut-on monter ?
|
||||
if m[1] == atout:
|
||||
has_atout = True
|
||||
if points_atout_order[m[0]]>maxpose:
|
||||
peutmonter = True
|
||||
break
|
||||
|
||||
# Il faut jouer de la couleur demandée
|
||||
if couldemandee != atout:
|
||||
if couldemandee in mains:
|
||||
if card[1]== couldemandee:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
if couldemandee == atout:
|
||||
# Il faut jouer atout (si possible)
|
||||
if has_atout:
|
||||
if card[1] != atout:
|
||||
return False
|
||||
# Et monter ! (si possible)
|
||||
if peutmonter:
|
||||
if points_atout_order[card[0]]<=maxpose:
|
||||
return False
|
||||
# Mais si on a pas, tant pis !
|
||||
return True
|
||||
|
||||
# Sinon, mon partenaire est-il maitre ?
|
||||
if len(playedl)>=2:
|
||||
maitre, xxx = winner(playedl, atout)
|
||||
if maitre == len(playedl)-2 :
|
||||
# Si oui, jeu libre
|
||||
return True
|
||||
|
||||
# Sinon, ai-je de l'atout ?
|
||||
if has_atout:
|
||||
if card[1] != atout:
|
||||
return False
|
||||
# Si oui, je dois monter si possible
|
||||
if peutmonter:
|
||||
if points_atout_order[card[0]] < maxpose:
|
||||
return False
|
||||
return True
|
||||
|
||||
# Sinon, jeu libre !
|
||||
return True
|
168
belote_ws.py
Normal file
@ -0,0 +1,168 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import flask_socketio as fio
|
||||
from flask_login import current_user
|
||||
from db import Game, Player, User
|
||||
from belote_jeu import translator, legal_play, colors, N_PLAYERS, N_TURN
|
||||
|
||||
NAME_ARBITRE = 'Arbitre'
|
||||
NAME_BONJOUR = 'Portier'
|
||||
|
||||
class CustomNamespacePlay(fio.Namespace):
|
||||
def __init__(self, id):
|
||||
self._id = id
|
||||
self.users = []
|
||||
fio.Namespace.__init__(self, '/game/{}'.format(id))
|
||||
def on_connect(self):
|
||||
if current_user is None or not self.game().authorized(current_user):
|
||||
fio.disconnect()
|
||||
if current_user.name not in self.users:
|
||||
if len(self.users)==1:
|
||||
fio.emit('text', {'text': '{} est là !'.format(self.users[0]), 'username':None, 'name':NAME_BONJOUR})
|
||||
elif len(self.users)>1:
|
||||
fio.emit('text', {'text': '{} est là !'.format(', '.join(self.users)), 'username':None, 'name':NAME_BONJOUR})
|
||||
self.users.append(current_user.name)
|
||||
fio.emit('text', {'text': '{} vient d\'arriver !'.format(current_user.name), 'username':None, 'name':NAME_BONJOUR}, broadcast=True)
|
||||
pass
|
||||
|
||||
def on_disconnect(self):
|
||||
if current_user.name in self.users:
|
||||
self.users.remove(current_user.name)
|
||||
fio.emit('text', {'text': '{} est parti.'.format(current_user.name), 'username':None, 'name':NAME_BONJOUR}, broadcast=True)
|
||||
pass
|
||||
|
||||
def on_join(self, data):
|
||||
pass
|
||||
|
||||
def on_choose_color(self, data):
|
||||
if 'atout' not in data:
|
||||
return
|
||||
atout = data['atout']
|
||||
|
||||
game = self.game()
|
||||
if not game.turn<0:
|
||||
fio.emit('text', {'text': "Choix d'atout indisponible", 'username':None, 'name':NAME_ARBITRE})
|
||||
return
|
||||
# C'est mon tour ?
|
||||
if game.get_nr(current_user) != (game.turn + game.first_player)%4:
|
||||
fio.emit('text', {'text': "Ce n'est pas votre tour...", 'username':None, 'name':NAME_ARBITRE})
|
||||
return
|
||||
# Choix légal pour ce tour ?
|
||||
if atout is not None and game.turn < -4 and game.played[1] != atout:
|
||||
fio.emit('text', {'text': "Pour l'instant on prend ou pas, mais on ne peut pas choisir l'atout.", 'username':None, 'name':NAME_ARBITRE})
|
||||
return
|
||||
if atout is not None and not atout in colors:
|
||||
fio.emit('text', {'text': "Couleur d'atout inconnue ({})".format(atout), 'username':None, 'name':NAME_ARBITRE})
|
||||
return
|
||||
# OK !
|
||||
print('atout choix')
|
||||
print(atout)
|
||||
if(game.tour_choix(atout, current_user)):
|
||||
print('Emit atout choix')
|
||||
fio.emit('choose_color', {'turn':game.turn, 'first_player':game.first_player, 'atout':game.atout, 'preneur':game.preneur if game.preneur is not None else current_user.login}, broadcast=True)
|
||||
else:
|
||||
fio.emit('text', {'text': "Erreur E0101", 'username':None, 'name':NAME_ARBITRE})
|
||||
|
||||
def on_play(self, data):
|
||||
if 'card' not in data:
|
||||
return
|
||||
card = data['card']
|
||||
|
||||
game = self.game()
|
||||
if game.turn<0:
|
||||
fio.emit('text', {'text': "Jeu pas encore disponible. Il faut choisir l'atout !", 'username':None, 'name':NAME_ARBITRE})
|
||||
return
|
||||
# C'est mon tour ?
|
||||
if game.get_nr(current_user) != (game.turn + game.first_player)%4:
|
||||
fio.emit('text', {'text': "Ce n'est pas votre tour...", 'username':None, 'name':NAME_ARBITRE})
|
||||
return
|
||||
# Choix légal pour ce tour ?
|
||||
p = game.get_player(current_user)
|
||||
if legal_play(game.played, game.atout, card, p.cards):
|
||||
ok, winnr = game.tour_jeu(card, current_user)
|
||||
if ok:
|
||||
fio.emit('play', {'turn':game.turn, 'played':game.played.split(',') if game.played is not None and game.played !='' else [], \
|
||||
'last_played':game.last_played.split(',') if game.last_played is not None else [] , 'first_player': game.first_player, 'points':[game.points_0, game.points_1]}, broadcast=True)
|
||||
else:
|
||||
fio.emit('text', {'text': "Vous ne pouvez pas jouer cette carte ({})".format(translator(card)), 'username':None, 'name':NAME_ARBITRE})
|
||||
return
|
||||
|
||||
def on_text(self, data):
|
||||
if 'text' in data and len(data['text'])>0:
|
||||
fio.emit('text', {'text':data['text'], 'username':current_user.login, 'name':current_user.name}, broadcast=True);
|
||||
|
||||
def on_monjeu(self, data):
|
||||
cards = self.game().get_player(current_user).cards
|
||||
cards = cards.split(',') if cards is not None and cards != '' else []
|
||||
fio.emit('monjeu', {'cards':cards});
|
||||
|
||||
def on_restart(self, data):
|
||||
game = self.game()
|
||||
if game.isadmin(current_user):
|
||||
if game.turn==N_TURN*N_PLAYERS:
|
||||
game.restart_jeu()
|
||||
fio.emit('restart', game.serialize_state_anonymous(), broadcast=True)
|
||||
else:
|
||||
fio.emit('text', {'text': "Finissez la partie avant d'en recommencer une.", 'username':None, 'name':NAME_ARBITRE})
|
||||
else:
|
||||
fio.emit('text', {'text': "Demandez au maitre du jeu pour reprendre une partie.", 'username':None, 'name':NAME_ARBITRE})
|
||||
|
||||
def game(self):
|
||||
return Game.query.get(self._id)
|
||||
|
||||
|
||||
class CustomNamespaceJoin(fio.Namespace):
|
||||
def __init__(self, id):
|
||||
self._id = id
|
||||
fio.Namespace.__init__(self, '/game/{}/join'.format(id))
|
||||
def on_connect(self):
|
||||
pass
|
||||
|
||||
def on_disconnect(self):
|
||||
pass
|
||||
|
||||
def on_join(self, data):
|
||||
if self.game().can_join(current_user):
|
||||
if not self.game().authorized(current_user):
|
||||
self.game().join(current_user)
|
||||
fio.emit('join', {'username':current_user.login, 'name': current_user.name}, broadcast=True)
|
||||
|
||||
def on_add_player(self, data):
|
||||
if self.game().isadmin(current_user):
|
||||
if 'username' in data:
|
||||
user = User.query.get(data['username'])
|
||||
if user is not None and self.game().can_join(user):
|
||||
if not self.game().authorized(user):
|
||||
self.game().join(user)
|
||||
fio.emit('join', {'username':user.login, 'name': user.name}, broadcast=True)
|
||||
|
||||
def on_leave(self, data):
|
||||
if self.game().leave(current_user):
|
||||
fio.emit('leave', {'username':current_user.login}, broadcast=True)
|
||||
|
||||
def on_ban(self, data):
|
||||
if 'username' in data:
|
||||
username = data['username']
|
||||
if self.game().isadmin(current_user):
|
||||
if 'username' is not None:
|
||||
if self.game().leave(username):
|
||||
fio.emit('leave', {'username':username})
|
||||
|
||||
def on_fixplayers(self, data):
|
||||
if self.game().isadmin(current_user):
|
||||
if self.game().can_start():
|
||||
self.game().fix_players()
|
||||
fio.emit('fixplayers', {})
|
||||
|
||||
def on_start(self, data):
|
||||
if 'order' in data:
|
||||
order = data['order']
|
||||
else:
|
||||
order = None
|
||||
if self.game().isadmin(current_user):
|
||||
if self.game().start_game(order):
|
||||
fio.emit('start', {}, broadcast=True)
|
||||
|
||||
def game(self):
|
||||
return Game.query.get(self._id)
|
||||
|
339
db.py
Normal file
@ -0,0 +1,339 @@
|
||||
from flask_login import UserMixin
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy.orm import relationship
|
||||
import random
|
||||
from belote_jeu import cards, N_PLAYERS, colors, winner, N_TURN
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
levels_users = {'Inactive':0, 'Simple user':1, 'Can create games':2, 'Can manage simple users': 8, 'Can manage games':9, 'Admin':10}
|
||||
|
||||
#######################################################################
|
||||
# User class #
|
||||
#######################################################################
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
"""Model for user accounts."""
|
||||
|
||||
__tablename__ = 'users'
|
||||
|
||||
login = db.Column(db.String(200),
|
||||
primary_key=True)
|
||||
name = db.Column(db.String(200),
|
||||
nullable=False,
|
||||
unique=False)
|
||||
password = db.Column(db.String(200),
|
||||
primary_key=False,
|
||||
unique=False,
|
||||
nullable=False)
|
||||
level = db.Column(db.Integer, default=1)
|
||||
last_login = db.Column(db.DateTime)
|
||||
|
||||
def set_password(self, password):
|
||||
"""Create hashed password."""
|
||||
self.password = generate_password_hash(password, method='sha256')
|
||||
|
||||
def check_password(self, password):
|
||||
"""Check hashed password."""
|
||||
return check_password_hash(self.password, password)
|
||||
|
||||
def get_id(self):
|
||||
return self.login
|
||||
|
||||
def __repr__(self):
|
||||
return '<User {}>'.format(self.login)
|
||||
|
||||
#######################################################################
|
||||
# Game class #
|
||||
#######################################################################
|
||||
|
||||
class Game(db.Model):
|
||||
__tablename__ = 'games'
|
||||
|
||||
id = db.Column(db.Integer,
|
||||
primary_key=True)
|
||||
name = db.Column(db.String(200))
|
||||
players = relationship("Player")
|
||||
turn = db.Column(db.Integer, default=-8)
|
||||
atout = db.Column(db.String(1))
|
||||
preneur = db.Column(db.Integer)
|
||||
admin = db.Column(db.String(200), db.ForeignKey('users.login'))
|
||||
cards_to_distribute = db.Column(db.String(200))
|
||||
first_player = db.Column(db.Integer)
|
||||
start = db.Column(db.Boolean, default=False)
|
||||
last_played = db.Column(db.String(20))
|
||||
played = db.Column(db.String(20))
|
||||
fixplayers = db.Column(db.Boolean, default=False)
|
||||
points_0 = db.Column(db.Integer, default=0)
|
||||
points_1 = db.Column(db.Integer, default=0)
|
||||
cumul_0 = db.Column(db.Integer, default=0)
|
||||
cumul_1 = db.Column(db.Integer, default=0)
|
||||
partie = db.Column(db.Integer, default=1)
|
||||
|
||||
def start_game(self, ordered_players):
|
||||
# Ordering players
|
||||
if self.fixplayers and not self.start:
|
||||
i=0
|
||||
if ordered_players is not None:
|
||||
for op in ordered_players:
|
||||
player = Player.query.filter_by(game=self.id, user=op).first()
|
||||
if player is not None:
|
||||
player.nr = i
|
||||
i+=1
|
||||
for p in self.players:
|
||||
if p.nr is None or p.nr<0:
|
||||
p.nr = i
|
||||
i+=1
|
||||
db.session.commit()
|
||||
|
||||
self.start = True
|
||||
self.first_player = 0
|
||||
self.distribute()
|
||||
db.session.commit()
|
||||
return True
|
||||
return False
|
||||
|
||||
def fix_players(self):
|
||||
if self.can_start():
|
||||
self.fixplayers = True
|
||||
db.session.commit()
|
||||
|
||||
def distribute(self):
|
||||
___cartes = random.sample(cards, k=len(cards))
|
||||
for i in range(len(self.players)):
|
||||
self.players[i].cards = ','.join(___cartes[5*i:5*(i+1)])
|
||||
self.played = ___cartes[5*(i+1)]
|
||||
self.cards_to_distribute = ','.join(___cartes[5*(i+1)+1:])
|
||||
|
||||
def authorized(self, user):
|
||||
for p in self.players:
|
||||
if user.login == p.user:
|
||||
return True
|
||||
return False
|
||||
|
||||
def isadmin(self, user):
|
||||
return user.login == self.admin
|
||||
|
||||
def serialize_state_anonymous(self):
|
||||
r = {}
|
||||
r['atout'] = self.atout
|
||||
r['preneur'] = self.preneur
|
||||
r['last_played'] = self.last_played.split(',') if self.last_played is not None else []
|
||||
r['played'] = self.played.split(',') if self.played is not None else []
|
||||
r['turn'] = self.turn
|
||||
r['first_player'] = self.first_player
|
||||
r['points'] = [self.points_0, self.points_1]
|
||||
r['cumul'] = [self.cumul_0, self.cumul_1]
|
||||
r['partie'] = self.partie
|
||||
return r
|
||||
|
||||
def serialize_state(self, user):
|
||||
r = self.serialize_state_anonymous()
|
||||
r['players'] = self.get_ordered_players()
|
||||
r['playersinfo'] = {}
|
||||
for p in self.players:
|
||||
r['playersinfo'][p.user] = User.query.get(p.user).name
|
||||
r['nr'] = self.get_nr(user)
|
||||
r['admin'] = self.admin
|
||||
cards = self.get_player(user).cards
|
||||
r['cards'] = cards.split(',') if cards is not None else []
|
||||
return r
|
||||
|
||||
def get_ordered_players(self):
|
||||
r = {}
|
||||
for p in self.players:
|
||||
r[p.nr] = p.user
|
||||
r2 = []
|
||||
for i in range(N_PLAYERS):
|
||||
r2.append(r[i] if i in r else None)
|
||||
return r2
|
||||
|
||||
def get_nr(self, user):
|
||||
p = self.get_player(user)
|
||||
if p is not None :
|
||||
return p.nr
|
||||
else:
|
||||
return -1
|
||||
|
||||
def get_player(self, user):
|
||||
if not isinstance(user, str):
|
||||
user = user.login
|
||||
return Player.query.filter_by(game=self.id, user=user).first()
|
||||
|
||||
def can_join(self, user):
|
||||
if self.authorized(user):
|
||||
return True
|
||||
if not self.fixplayers and len(self.players) < N_PLAYERS:
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_start(self):
|
||||
if len(self.players)==N_PLAYERS:
|
||||
return True
|
||||
return False
|
||||
|
||||
def join(self, user):
|
||||
if not self.fixplayers and not self.authorized(user):
|
||||
p = Player(game=self.id, user=user.login)
|
||||
db.session.add(p)
|
||||
db.session.commit()
|
||||
|
||||
def leave(self, user):
|
||||
if not self.fixplayers:
|
||||
for p in self.players:
|
||||
if isinstance(user, str) and user != self.admin or hasattr(user, 'login') and user.login != self.admin:
|
||||
if isinstance(user, str) and user == p.user or hasattr(user, 'login') and user.login == p.user:
|
||||
db.session.delete(p)
|
||||
db.session.commit()
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_players(self):
|
||||
r = []
|
||||
for p in self.players:
|
||||
user = User.query.get(p.user)
|
||||
r.append({'username':user.login, 'name':user.name})
|
||||
return r
|
||||
|
||||
def tour_choix(self, atout, user):
|
||||
if (self.turn + self.first_player) % N_PLAYERS == self.get_nr(user):
|
||||
self.turn += 1
|
||||
if atout is not None and atout in colors:
|
||||
self.atout = atout
|
||||
self.preneur = user.login
|
||||
self.turn = 0
|
||||
self.distribute_restant()
|
||||
db.session.commit()
|
||||
return True
|
||||
return False
|
||||
|
||||
def distribute_restant(self):
|
||||
todistribute = self.cards_to_distribute.split(',')
|
||||
for pn in self.get_ordered_players():
|
||||
p = self.get_player(pn)
|
||||
if pn == self.preneur:
|
||||
p.cards += ',' + ','.join(todistribute[:2])
|
||||
p.cards += ',' + self.played
|
||||
todistribute = todistribute[2:]
|
||||
else:
|
||||
p.cards += ',' + ','.join(todistribute[:3])
|
||||
todistribute = todistribute[3:]
|
||||
self.cards_to_distribute = ''
|
||||
self.played = None
|
||||
|
||||
def tour_jeu(self, carte, user):
|
||||
if (self.turn + self.first_player) % N_PLAYERS == self.get_nr(user):
|
||||
winnr = -1
|
||||
self.turn += 1
|
||||
if self.played is None or self.played == '':
|
||||
self.played = carte
|
||||
else:
|
||||
self.played += ',' + carte
|
||||
if self.turn % N_PLAYERS == 0 :
|
||||
winnr, points = winner(self.played, self.atout)
|
||||
if (self.first_player + winnr)%2 == 0:
|
||||
self.points_0 += points
|
||||
else:
|
||||
self.points_1 += points
|
||||
self.last_played = self.played
|
||||
if len(self.cards_to_distribute)>1:
|
||||
self.cards_to_distribute += ','
|
||||
self.cards_to_distribute += self.played
|
||||
self.played = None
|
||||
self.first_player = (self.first_player + winnr)%4
|
||||
if self.turn == N_TURN*N_PLAYERS: # Dix de der, chute, belote et capote !
|
||||
if (self.first_player + winnr)%2 == 0:
|
||||
self.points_0 += 10
|
||||
else:
|
||||
self.points_1 += 10
|
||||
if self.get_player(self.preneur).nr %2 ==0 and self.points_0 < self.points_1:
|
||||
self.points_0 = 0
|
||||
self.points_1 = 162
|
||||
if self.get_player(self.preneur).nr %2 ==1 and self.points_1 < self.points_0:
|
||||
self.points_0 = 162
|
||||
self.points_1 = 0
|
||||
if self.points_0 == 162 or self.points_1 == 162:
|
||||
winequipe = 0 if self.points_0 == 162 else 1
|
||||
# Capote possible.
|
||||
winnr = 0
|
||||
ccc = self.cards_to_distribute.split(',')
|
||||
for i in range(N_TURN):
|
||||
win, xxx = winner(ccc[i*N_PLAYERS:(i+1)*N_PLAYERS], self.atout)
|
||||
winnr = win+winnr
|
||||
if winnr % 2 != winequipe:
|
||||
break
|
||||
else:
|
||||
if winequipe == 0:
|
||||
self.points_0 += 90
|
||||
else:
|
||||
self.points_1 += 90
|
||||
# belote possible
|
||||
winnr = 0
|
||||
belote =-1
|
||||
ccc = self.cards_to_distribute.split(',')
|
||||
for i in range(N_TURN):
|
||||
cccc = ccc[i*N_PLAYERS:(i+1)*N_PLAYERS]
|
||||
if 'R'+self.atout in cccc:
|
||||
if belote>=0:
|
||||
if (cccc.index('R'+self.atout) + winnr)%4 == belote %4:
|
||||
if belote %2 ==0:
|
||||
self.points_0 += 20
|
||||
else:
|
||||
self.points_1 += 20
|
||||
else:
|
||||
belote = winnr + cccc.index('R'+self.atout)
|
||||
if 'D'+self.atout in cccc:
|
||||
if belote>=0:
|
||||
if (cccc.index('D'+self.atout) + winnr)%4 == belote %4:
|
||||
if belote %2 ==0:
|
||||
self.points_0 += 20
|
||||
else:
|
||||
self.points_1 += 20
|
||||
else:
|
||||
belote = winnr + cccc.index('D'+self.atout)
|
||||
win, xxx = winner(cccc, self.atout)
|
||||
winnr = win+winnr
|
||||
# Retirer la carte du jeu !
|
||||
p = self.get_player(user)
|
||||
ccc = p.cards
|
||||
ccc = ccc.split(',')
|
||||
ccc.remove(carte)
|
||||
p.cards = ','.join(ccc)
|
||||
db.session.commit()
|
||||
return True, winnr
|
||||
return False, -1
|
||||
|
||||
def restart_jeu(self):
|
||||
if self.turn==N_TURN*N_PLAYERS:
|
||||
self.turn = -8
|
||||
self.atout = None
|
||||
self.preneur = None
|
||||
self.last_played = None
|
||||
self.played = None
|
||||
self.cumul_0 += self.points_0
|
||||
self.cumul_1 += self.points_1
|
||||
self.points_0 = 0
|
||||
self.points_1 = 0
|
||||
self.partie +=1
|
||||
self.first_player = 0
|
||||
self.distribute()
|
||||
db.session.commit()
|
||||
return True
|
||||
return False
|
||||
|
||||
#######################################################################
|
||||
# Player class #
|
||||
#######################################################################
|
||||
|
||||
class Player(db.Model):
|
||||
__tablename__ = 'players'
|
||||
|
||||
id = db.Column(db.Integer,
|
||||
primary_key=True)
|
||||
game = db.Column(db.Integer, db.ForeignKey('games.id'))
|
||||
user = db.Column(db.Integer, db.ForeignKey('users.login'))
|
||||
cards = db.Column(db.String(40))
|
||||
nr = db.Column(db.Integer, default=-1)
|
||||
|
||||
|
7
requirements.txt
Normal file
@ -0,0 +1,7 @@
|
||||
Flask==1.1.2
|
||||
Flask-Login==0.5.0
|
||||
Flask-SocketIO==4.2.1
|
||||
Flask-SQLAlchemy==2.4.1
|
||||
SQLAlchemy==1.3.16
|
||||
Werkzeug==1.0.1
|
||||
eventlet==0.25.2
|
9
settings.exemple.cfg
Normal file
@ -0,0 +1,9 @@
|
||||
# App configuration file
|
||||
# copy this file to settings.cfg
|
||||
|
||||
# Generate a secure key with
|
||||
# python -c "import os, base64; print(base64.b64encode(os.urandom(24)))"
|
||||
SECRET_KEY = "to-be-changed"
|
||||
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite'
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
73
static/belote-script.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*************************
|
||||
la Belote
|
||||
**************************/
|
||||
var go = function(url) {
|
||||
document.location.href=url;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
/*==============================
|
||||
listeners à activer à ready
|
||||
===============================*/
|
||||
|
||||
document.getElementById("username").addEventListener("click",function() {apparaitDisparaitMenu('username-items','username-fleche')});
|
||||
|
||||
var options = document.getElementById("options");
|
||||
if(options){
|
||||
options.addEventListener("click",function() {apparaitDisparaitAccordeon('options-valeur','options-fleche')});
|
||||
}
|
||||
var derpli = document.getElementById("dernier-pli")
|
||||
if(derpli){
|
||||
derpli.addEventListener("click",function() {apparaitDisparaitAccordeon('dernier-pli-valeur','dernier-pli-fleche')});
|
||||
}
|
||||
|
||||
|
||||
/*==============================
|
||||
fonctions
|
||||
===============================*/
|
||||
/*
|
||||
fonction apparaitDisparaitUserAttr
|
||||
apparition/disparition d'un menu
|
||||
*/
|
||||
function apparaitDisparaitMenu (idMenu,idFleche) {
|
||||
var element = document.getElementById(idMenu);
|
||||
if(element.style.visibility == "hidden" || element.style.visibility == "") {
|
||||
document.getElementById(idMenu).style.visibility = "visible";
|
||||
}
|
||||
else {
|
||||
document.getElementById(idMenu).style.visibility = "hidden";
|
||||
};
|
||||
var elementFleche = document.getElementById(idFleche);
|
||||
var splitElement = elementFleche.src.split('/');
|
||||
var lastElement = splitElement[splitElement.length-1];
|
||||
if(lastElement == "fleche-bas.gif") {
|
||||
document.getElementById(idFleche).src = "/static/fleche-haut.gif";
|
||||
}
|
||||
else {
|
||||
document.getElementById(idFleche).src = "/static/fleche-bas.gif";
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
function apparaitDisparaitAccordeon (idZone,idFleche) {
|
||||
var element = document.getElementById(idZone);
|
||||
if(element.style.display == "none" || element.style.display == "") {
|
||||
document.getElementById(idZone).style.display = "block";
|
||||
}
|
||||
else {
|
||||
document.getElementById(idZone).style.display = "none";
|
||||
};
|
||||
var elementFleche = document.getElementById(idFleche);
|
||||
var splitElement = elementFleche.src.split('/');
|
||||
var lastElement = splitElement[splitElement.length-1];
|
||||
if(lastElement == "fleche-bas.gif") {
|
||||
document.getElementById(idFleche).src = "/static/fleche-haut.gif";
|
||||
}
|
||||
else {
|
||||
document.getElementById(idFleche).src = "/static/fleche-bas.gif";
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* fin de $(document).ready() */
|
||||
});
|
391
static/belote.css
Normal file
@ -0,0 +1,391 @@
|
||||
/* =========================
|
||||
la Belote
|
||||
========================= */
|
||||
/****************/
|
||||
/* Reset */
|
||||
/****************/
|
||||
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;vertical-align:baseline;background:transparent}
|
||||
body{line-height:1}
|
||||
ol,ul{list-style:none}
|
||||
blockquote,q{quotes:none}
|
||||
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}
|
||||
:focus{outline:0}
|
||||
ins{text-decoration:none}
|
||||
del{text-decoration:line-through}
|
||||
table{border-collapse:collapse;border-spacing:0}
|
||||
/****************/
|
||||
/* généralités */
|
||||
/****************/
|
||||
body {
|
||||
margin: 0px;
|
||||
background-color: #13995E;
|
||||
}
|
||||
div.clear {
|
||||
clear: both;
|
||||
}
|
||||
div.clearfix-head::after {
|
||||
content:"";
|
||||
clear: both;
|
||||
display: table;
|
||||
border: 1px solid black;
|
||||
width: 100%;
|
||||
}
|
||||
div.clearfix::after{
|
||||
content:"";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
div, p, li, a, th, td {
|
||||
font-family: 'Segoe UI', Arial, Helvetica, sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 17px;
|
||||
color: #092E1E;
|
||||
}
|
||||
/****************/
|
||||
/* conteneur */
|
||||
/****************/
|
||||
#conteneur {
|
||||
margin-top: 8px;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0px;
|
||||
margin-left: auto;
|
||||
height: 600px;
|
||||
width: 1200px;
|
||||
/* border: 1px solid #092E1E; */
|
||||
}
|
||||
/****************/
|
||||
/* entete */
|
||||
/****************/
|
||||
#entete {
|
||||
position: relative;
|
||||
height: 66px;
|
||||
margin: 2px;
|
||||
/*
|
||||
border: 1px solid #092E1E;
|
||||
*/
|
||||
}
|
||||
#logo {
|
||||
margin: 2px 10px 2px 2px;
|
||||
float: left;
|
||||
}
|
||||
#logo img {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
#titre {
|
||||
width: 55%;
|
||||
line-height: 60px;
|
||||
margin: 2px 15px 2px 2px;
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
}
|
||||
#username {
|
||||
width: 20%;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
margin: 2px 15px 2px 30px;
|
||||
float: right;
|
||||
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
#username-fleche {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
cursor: pointer;
|
||||
padding-left: 10px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
#username-items {
|
||||
position: absolute;
|
||||
top: 68px;
|
||||
right: 0px;
|
||||
width: 180px;
|
||||
visibility: hidden;
|
||||
margin-top: 2px ;
|
||||
padding: 5px;
|
||||
border: 1px solid #092E1E;
|
||||
overflow: hidden;
|
||||
z-index: 100;
|
||||
background-color: #b7a86b;
|
||||
}
|
||||
.menu-item:hover {
|
||||
cursor: pointer;
|
||||
background-color: #15A160;
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* zone-de-contenu */
|
||||
/****************/
|
||||
#zone-de-contenu {
|
||||
width:50%;
|
||||
margin:auto;
|
||||
}
|
||||
#zone-de-contenu>div {
|
||||
margin:auto;
|
||||
}
|
||||
.tablelist {
|
||||
width:100%;
|
||||
}
|
||||
/****************/
|
||||
/* zone-de-jeu */
|
||||
/****************/
|
||||
#zone-de-jeu {
|
||||
height: 438px;
|
||||
margin: 2px;
|
||||
/*
|
||||
border: 1px solid #092E1E;
|
||||
*/
|
||||
}
|
||||
#plateau {
|
||||
height: 320px;
|
||||
width: 740px;
|
||||
position: relative;
|
||||
margin: 3px;
|
||||
}
|
||||
#joueur-0 {
|
||||
position: absolute;
|
||||
top: 55px;
|
||||
left: 190px;
|
||||
text-align: right;
|
||||
}
|
||||
#joueur-1 {
|
||||
position: absolute;
|
||||
top: 145px;
|
||||
left: 80px;
|
||||
text-align: right;
|
||||
}
|
||||
#joueur-2 {
|
||||
position: absolute;
|
||||
top: 245px;
|
||||
left: 190px;
|
||||
text-align: right;
|
||||
}
|
||||
#joueur-3 {
|
||||
position: absolute;
|
||||
top: 145px;
|
||||
left: 500px;
|
||||
}
|
||||
#jeu-0 {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: 300px;
|
||||
}
|
||||
#jeu-1 {
|
||||
position: absolute;
|
||||
top: 120px;
|
||||
left: 190px;
|
||||
}
|
||||
#jeu-2 {
|
||||
position: absolute;
|
||||
top: 220px;
|
||||
left: 300px;
|
||||
}
|
||||
#jeu-3 {
|
||||
position: absolute;
|
||||
top: 120px;
|
||||
left: 420px;
|
||||
}
|
||||
#suivant {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 90px;
|
||||
}
|
||||
#suivant input {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
#ov {
|
||||
height: 310px;
|
||||
width: 390px;
|
||||
padding: 5px 25px 5px 25px;
|
||||
position: relative;
|
||||
top: -322px;
|
||||
left: 746px;
|
||||
margin: 2px;
|
||||
border: 1px solid #092E1E;
|
||||
|
||||
}
|
||||
#table-atout {
|
||||
width: 98%;
|
||||
}
|
||||
#table-atout td {
|
||||
padding: 4px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#atout {
|
||||
margin: 0px auto 0px auto;
|
||||
}
|
||||
#choix {
|
||||
height: 160px;
|
||||
margin-top: 25px;
|
||||
padding: 6px;
|
||||
border: 1px solid #092E1E;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#options-fleche {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
#options-valeur {
|
||||
display: none;
|
||||
}
|
||||
#dernier-pli-fleche {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
#dernier-pli-valeur {
|
||||
display: none;
|
||||
}
|
||||
#dernier-pli {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#dernier-pli-valeur {
|
||||
padding-left: 50px;
|
||||
}
|
||||
#jeu-en-main {
|
||||
height: 76px;
|
||||
width: 642px;
|
||||
position: relative;
|
||||
top: -320px;
|
||||
left: 0px;
|
||||
margin: 2px;
|
||||
padding: 15px 58px 15px 40px;
|
||||
border: 1px solid #092E1E;
|
||||
}
|
||||
#a-vous {
|
||||
float: left;
|
||||
width: 90px;
|
||||
height: 79px;
|
||||
padding-top: 20px;
|
||||
text-align: center;
|
||||
margin-right: 20px;
|
||||
visibility: hidden;
|
||||
}
|
||||
#points {
|
||||
height: 98px;
|
||||
width: 390px;
|
||||
position: relative;
|
||||
top: -430px;
|
||||
left: 746px;
|
||||
margin: 2px;
|
||||
border: 1px solid #092E1E;
|
||||
padding: 4px 25px 4px 25px;
|
||||
}
|
||||
#points p {
|
||||
text-align: center;
|
||||
margin: 5px 0px 5px 0px;
|
||||
}
|
||||
#points table {
|
||||
width: 98%;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #092E1E;
|
||||
}
|
||||
#points table td {
|
||||
padding: 0px 2px 0px 2px;
|
||||
text-align: center;
|
||||
border: 1px solid #092E1E;
|
||||
}
|
||||
.joueur {
|
||||
width: 90px;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
text-decoration: underscore;
|
||||
}
|
||||
.carte {
|
||||
height: 77px;
|
||||
width: 50px;
|
||||
/* carte : hauteur = 1,54 * largueur; */
|
||||
border: 1px solid #092E1E;
|
||||
background-color: #117F4A;
|
||||
}
|
||||
.carte-en-main, .carte-dernier-pli {
|
||||
float: left;
|
||||
margin-right: 12px;
|
||||
}
|
||||
.item-choix {
|
||||
padding: 4px;
|
||||
border: 1px solid #092E1E;
|
||||
}
|
||||
.item-choix-valeur {
|
||||
padding: 4px;
|
||||
border-right: 1px solid #092E1E;
|
||||
border-bottom: 1px solid #092E1E;
|
||||
border-left: 1px solid #092E1E;
|
||||
}
|
||||
/************************/
|
||||
/* zone-de-conversation */
|
||||
/************************/
|
||||
#zone-de-conversation {
|
||||
height: 84px;
|
||||
margin: 2px;
|
||||
/*
|
||||
border: 1px solid #092E1E;
|
||||
*/
|
||||
position: relative;
|
||||
}
|
||||
#chat {
|
||||
width: 61%;
|
||||
height: 87%;
|
||||
float: left;
|
||||
background-color: #C4E8D7;
|
||||
margin: 2px 15px 2px 2px;
|
||||
border-top: 2px solid #888;
|
||||
border-right: 2px solid #DDD;
|
||||
border-bottom: 2px solid #DDD;
|
||||
border-left: 2px solid #888;
|
||||
position: absolute;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#message {
|
||||
width: 34%;
|
||||
float: right;
|
||||
margin: 1px 15px 2px 2px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 3px;
|
||||
}
|
||||
#message p {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
#texte-msg {
|
||||
width:80%;
|
||||
background-color: #C4E8D7;
|
||||
margin-right: 5px;
|
||||
}
|
||||
button#add{
|
||||
min-width:180px;
|
||||
margin:auto;
|
||||
padding:10px;
|
||||
background: #b7a86b;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
-khtml-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
display:block;
|
||||
}
|
||||
|
||||
thead{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
fieldset.fieldset {
|
||||
border:1px solid green;
|
||||
padding:30px;
|
||||
margin:20px;
|
||||
}
|
BIN
static/cards/0C.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/cards/0F.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/cards/0P.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/cards/0T.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
static/cards/7C.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
static/cards/7F.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
static/cards/7P.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
static/cards/7T.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/cards/8C.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/cards/8F.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
static/cards/8P.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
static/cards/8T.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/cards/9C.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/cards/9F.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/cards/9P.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/cards/9T.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/cards/AC.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
static/cards/AF.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
static/cards/AP.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
static/cards/AT.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/cards/C.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
static/cards/DC.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
static/cards/DF.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
static/cards/DP.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
static/cards/DT.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
static/cards/F.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
static/cards/P.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
static/cards/RC.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
static/cards/RF.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
static/cards/RP.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
static/cards/RT.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
static/cards/T.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
static/cards/VC.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
static/cards/VF.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
static/cards/VP.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
static/cards/VT.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
static/croix.png
Normal file
After Width: | Height: | Size: 326 B |
BIN
static/edit.png
Normal file
After Width: | Height: | Size: 719 B |
BIN
static/fleche-bas.gif
Normal file
After Width: | Height: | Size: 76 B |
BIN
static/fleche-haut.gif
Normal file
After Width: | Height: | Size: 76 B |
262
static/game_script.js
Normal file
@ -0,0 +1,262 @@
|
||||
var socket = null;
|
||||
var sendtext = function(){
|
||||
var text = $('#texte-msg').val();
|
||||
if (text.length > 1){
|
||||
$('#texte-msg').val('');
|
||||
socket.emit('text', {'text':text});
|
||||
}
|
||||
};
|
||||
|
||||
var choixcouleur = function(coul){
|
||||
socket.emit('choose_color', {'atout':coul});
|
||||
}
|
||||
|
||||
var jouer = function(carte, no){
|
||||
socket.emit('play', {'card':carte});
|
||||
}
|
||||
var restart_jeu = function(){
|
||||
socket.emit('restart', {});
|
||||
}
|
||||
|
||||
|
||||
$.fn.pressEnter = function (fnc) {
|
||||
return this.each(function () {
|
||||
$(this).keypress(function (ev) {
|
||||
var keycode = (ev.keyCode ? ev.keyCode : ev.which);
|
||||
if (keycode == '13') {
|
||||
fnc.call(this, ev);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var set_points = function(){
|
||||
$('#nous-tot').html( jeu['cumul'][jeu['nr']%2] );
|
||||
$('#nous-part').html(jeu['points'][jeu['nr']%2] );
|
||||
$('#eux-tot').html( jeu['cumul'][(jeu['nr']+1)%2] );
|
||||
$('#eux-part').html( jeu['points'][(jeu['nr']+1)%2]);
|
||||
$('#nopart').html('Partie '+jeu['partie']);
|
||||
}
|
||||
|
||||
var set_atout = function(){
|
||||
if(jeu['atout'] == null || jeu['atout']==''){
|
||||
var coulprop = jeu['played'][0];
|
||||
$('#atout').html(`<img src="/static/cards/${coulprop}.png" width=100% />`);
|
||||
if (jeu['turn']<-4 && (jeu['turn']+jeu['first_player']+8)%4 == jeu['nr']){
|
||||
$('#prispar').html(`<input type="submit" onclick="javascript:choixcouleur('${coulprop[1]}')" value="Prendre" />`);
|
||||
$('#preneur').html(`<input type="submit" onclick="javascript:choixcouleur(null)" value="Passer" />`);
|
||||
}else if((jeu['turn']+jeu['first_player']+8)%4 == jeu['nr']){
|
||||
$('#prispar').html(`<input type="submit" onclick="javascript:choixcouleur('P')" value="Pique" />
|
||||
<input type="submit" onclick="javascript:choixcouleur('C')" value="Coeur" />
|
||||
<br />
|
||||
<input type="submit" onclick="javascript:choixcouleur('T')" value="Trèfle" />
|
||||
<input type="submit" onclick="javascript:choixcouleur('F')" value="Carreau" />
|
||||
`);
|
||||
$('#preneur').html(`<input type="submit" onclick="javascript:choixcouleur(null)" value="Passer" />`);
|
||||
}else{
|
||||
$('#prispar').html(`Pris par`);
|
||||
$('#preneur').html(`----`);
|
||||
}
|
||||
}else{
|
||||
$('#atout').html(`<img src="/static/cards/${jeu['atout']}.png" width=100% />`);
|
||||
$('#prispar').html(`Pris par`);
|
||||
$('#preneur').html(`${jeu['playersinfo'][jeu['preneur']]}`);
|
||||
}
|
||||
}
|
||||
|
||||
jeu['monjeu'] = Array.from(jeu['cards']);
|
||||
var order = ['A', '0', 'R', 'D', 'V', '9', '8', '7'];
|
||||
var order_atout = ['V', '9', 'A', '0', 'R', 'D', '8', '7'];
|
||||
var set_jeu = function(){
|
||||
var order_colors = ['P', 'C', 'T', 'F'];
|
||||
if (jeu['atout'] == 'C'){
|
||||
order_colors = ['C', 'T', 'F', 'P'];
|
||||
}else if (jeu['atout'] == 'T'){
|
||||
order_colors = ['T', 'C', 'P', 'F'];
|
||||
}else if (jeu['atout'] == 'F'){
|
||||
order_colors = ['F', 'T', 'C', 'P'];
|
||||
}
|
||||
jeu['monjeu'].sort(function(a,b){
|
||||
if (a[1]==jeu['atout']){
|
||||
x = order_atout.indexOf(a[0]);
|
||||
}else{
|
||||
x = order.indexOf(a[0]);
|
||||
}
|
||||
if (b[1]==jeu['atout']){
|
||||
y = order_atout.indexOf(b[0]);
|
||||
}else{
|
||||
y = order.indexOf(b[0]);
|
||||
}
|
||||
return x+15*order_colors.indexOf(a[1]) > y+15*order_colors.indexOf(b[1]) ? 1 : -1;
|
||||
});
|
||||
console.log(jeu['monjeu']);
|
||||
|
||||
for(i=0;i<jeu['monjeu'].length;i++){
|
||||
if (jeu['monjeu'][i]==null){
|
||||
$('#carte-'+i).html('');
|
||||
}else{
|
||||
$('#carte-'+i).html(`<a href="javascript:jouer('${jeu['monjeu'][i]}', ${i})"><img src="/static/cards/${jeu['monjeu'][i]}.png" width=100% /></a>`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var set_cartes = function(){
|
||||
first_player = jeu['first_player']
|
||||
if (jeu['turn']%4==0 && 'lastfirstplayer' in jeu){
|
||||
first_player = jeu['lastfirstplayer']
|
||||
}
|
||||
if (jeu['preneur'] == null){
|
||||
$('#jeu-1').html('');
|
||||
$('#jeu-2').html('');
|
||||
$('#jeu-3').html('');
|
||||
$('#jeu-4').html('');
|
||||
}else{
|
||||
for(i=first_player;i<first_player+4;i++){
|
||||
j = i-first_player
|
||||
k = i%4
|
||||
if (jeu['played'].length > j && jeu['played'][j]!= ''){
|
||||
$('#jeu-'+ k).html(`<img src="/static/cards/${jeu['played'][j]}.png" width=100% />`);
|
||||
}else{
|
||||
$('#jeu-'+ k).html('');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var set_derpli = function(){
|
||||
if(jeu['last_played'].length >0){
|
||||
for(i=0;i<4;i++){
|
||||
$('#der-pli-'+i).html(`<img src="/static/cards/${jeu['last_played'][i]}.png" width=100% />`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var set_players = function(){
|
||||
for(i=0;i<4;i++){
|
||||
$('#joueur-'+i).html(`${jeu['playersinfo'][jeu['players'][i]]}`);
|
||||
}
|
||||
}
|
||||
|
||||
var set_current_player = function(){
|
||||
for(i=0;i<4;i++){
|
||||
$('#joueur-'+i).css('font-weight', 'normal');
|
||||
}
|
||||
i = (jeu['turn']+jeu['first_player']+8)%4;
|
||||
$('#joueur-'+i).css('font-weight', 'bold');
|
||||
if((jeu['turn']+jeu['first_player']+8)%4 == jeu['nr']){
|
||||
$('#a-vous').css('visibility', 'visible');
|
||||
}else{
|
||||
$('#a-vous').css('visibility', 'hidden');
|
||||
}
|
||||
|
||||
if(jeu['turn']==32 && jeu['admin']==jeu['players'][jeu['nr']]){
|
||||
$('#suivant').show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
socket = io(window.location.pathname);
|
||||
$('#suivant').hide()
|
||||
set_points();
|
||||
set_atout();
|
||||
set_jeu();
|
||||
set_cartes();
|
||||
set_derpli();
|
||||
set_players();
|
||||
set_current_player();
|
||||
|
||||
for (e in jeu){
|
||||
$('#jeu').append(`${e} : ${jeu[e]} <br />`)
|
||||
}
|
||||
if((jeu['turn']+jeu['first_player'] + 8)%4 == jeu['nr']){
|
||||
$('#a-vous').css('visibility', 'visible');
|
||||
}
|
||||
|
||||
|
||||
socket.on('connect', function() {
|
||||
socket.emit('join', {data: 'I\'m connected!'});
|
||||
});
|
||||
|
||||
socket.on('text', function(data) {
|
||||
textr = data['text'];
|
||||
name = data['name'];
|
||||
$('#chat').prepend(`<b>${name}</b> : ${textr}<br />`);
|
||||
});
|
||||
|
||||
socket.on('restart', function(data) {
|
||||
for(d in data){
|
||||
jeu[d] = data[d]
|
||||
}
|
||||
set_points();
|
||||
set_atout();
|
||||
set_cartes();
|
||||
set_derpli();
|
||||
set_players();
|
||||
set_current_player();
|
||||
socket.emit('monjeu', {});
|
||||
});
|
||||
|
||||
socket.on('choose_color', function(data){
|
||||
console.log(data)
|
||||
jeu['turn'] = data['turn']
|
||||
jeu['preneur'] = data['preneur']
|
||||
jeu['atout'] = data['atout']
|
||||
set_atout();
|
||||
set_current_player();
|
||||
if(jeu['turn']>=0){
|
||||
socket.emit('monjeu', {});
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('monjeu', function(data){
|
||||
jeu['cards'] = data['cards'];
|
||||
jeu['monjeu'] = Array.from(data['cards']);
|
||||
set_jeu();
|
||||
});
|
||||
|
||||
socket.on('play', function(data){
|
||||
console.log(data)
|
||||
jeu['turn'] = data['turn'];
|
||||
jeu['lastfirstplayer'] = jeu['first_player']
|
||||
jeu['first_player'] = data['first_player'];
|
||||
jeu['last_played'] = data['last_played'];
|
||||
jeu['points'] = data['points'];
|
||||
if(data['played'] == null || data['played'].length == 0){
|
||||
jeu['played'] = data['last_played'];
|
||||
console.log(jeu['played'])
|
||||
set_cartes();
|
||||
set_derpli();
|
||||
set_points();
|
||||
}
|
||||
else{
|
||||
jeu['played'] = data['played'];
|
||||
console.log(jeu['played'])
|
||||
set_cartes();
|
||||
set_points();
|
||||
}
|
||||
var first_player = jeu['first_player'];
|
||||
if (jeu['turn']%4==0 && 'lastfirstplayer' in jeu){
|
||||
first_player = jeu['lastfirstplayer']
|
||||
}
|
||||
if((jeu['turn']+first_player+7)%4 == jeu['nr']){
|
||||
console.log("Je viens de jouer")
|
||||
i = jeu['monjeu'].indexOf(jeu['played'][jeu['played'].length-1]);
|
||||
if (jeu['played'].length>0 && i >=0){
|
||||
console.log(i)
|
||||
jeu['monjeu'][i] = null;
|
||||
$('#carte-'+i).html('')
|
||||
}
|
||||
|
||||
}
|
||||
set_current_player();
|
||||
});
|
||||
|
||||
|
||||
$('#texte-msg').pressEnter(function(e){
|
||||
sendtext();
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
BIN
static/logo.gif
Normal file
After Width: | Height: | Size: 849 B |
BIN
static/ok.png
Normal file
After Width: | Height: | Size: 506 B |
BIN
static/plus.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
28
templates/admin_game_add.html
Normal file
@ -0,0 +1,28 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Créer jeu {% endblock %}
|
||||
|
||||
{% block titre %} Créer un jeu {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<div style="width:100%;margin:20px;"> </div>
|
||||
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Nom du jeu</legend>
|
||||
{% for message in get_flashed_messages() %}
|
||||
<div class="alert alert-warning">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<form action="" method="POST" accept-charset="utf-8">
|
||||
Nom du jeu : <input type="text" name="name" id="name" placeholder="Nom du jeu"/><br />
|
||||
Maitre du jeu : <input type="text" name="admin" placeholder="Login du maitre du jeu" /><br />
|
||||
<input id="submit" type="submit" value="Créer">
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
27
templates/admin_games.html
Normal file
@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Administration {% endblock %}
|
||||
|
||||
{% block titre %}Administration : jeux {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<fieldset class="fieldset" ><legend style="font-size:25px;">Ajouter un utilisateur</legend>
|
||||
<button id="add" onclick="javascript:go('/admin/games/new')">
|
||||
<img src="/static/plus.png" style="float:left;" alt=''/><div style="float:right; margin:5px;">Nouveau jeu</div>
|
||||
</button>
|
||||
</fieldset>
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Liste des jeux</legend>
|
||||
<table width=100%>
|
||||
<thead>
|
||||
<tr><td>Id</td><td>Name</td><td>Partie</td><td>Joueurs</td><td>Status</td><td>Actions</td></tr>
|
||||
</thead>
|
||||
{% for g in games %}
|
||||
<tr><td>{{ g.id }}</td><td><a href="/game/{{g.id}}">{{ g.name }}</a></td><td>{{ g.partie }}</td><td>{% for p in g.players %}{{ p.user }} {% endfor %}</td>
|
||||
<td>{% if g.start %} Started {% elif g.fixplayers %}Players set{% else %}Join{% endif %}</td>
|
||||
<td><a href="/game/{{g.id}}/see">Voir</a> <a href="/admin/games/{{ g.id }}/del"><img src="/static/croix.png" alt="Del" /></a></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
{% endblock %}
|
17
templates/admin_user_del.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Jeux {% endblock %}
|
||||
|
||||
{% block titre %} Suppression utilisateur {{ useredit.name }} {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Confirmation</legend>
|
||||
<p>Sur de vouloir supprimer l'utilisateur <b>{{ useredit.name }} ({{useredit.login}})</b> ? </p>
|
||||
<br />
|
||||
<table width=100% style="text-align:center">
|
||||
<tr><td><a href="?confirm=1">Oui</a></td><td> <a href="/admin/users">Non</a></td></tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
{% endblock %}
|
40
templates/admin_user_edit.html
Normal file
@ -0,0 +1,40 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Administration {% endblock %}
|
||||
|
||||
{% block titre %} Administration : Éditer un utilisateur {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<form method="POST" action="">
|
||||
<div style="width:100%;margin:20px;"> </div>
|
||||
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Utilisateur</legend>
|
||||
{% for message in get_flashed_messages() %}
|
||||
<div class="alert alert-warning">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<table width=100%>
|
||||
<tr><td>Nom d'utilisateur : </td><td> <input type="text" name="username" placeholder="jean.dupont" {% if useredit is not none %} value="{{useredit.login}}" readonly="readonly"{% endif %} /></td></tr>
|
||||
<tr><td>Nom complet : </td><td> <input type="text" name="name" placeholder="Mr Jean Dupont" {% if useredit is not none %} value="{{useredit.name}}" {% endif %} /></td></tr>
|
||||
<tr><td> Mot de passe : </td><td> <input type="password" name="password" placeholder="Mot de passe"/></td></tr>
|
||||
<tr><td> Droits : </td><td> <select name="level">
|
||||
{% for e in levels_users %}
|
||||
{% if useredit is none %}
|
||||
<option value="{{ levels_users[e] }}" {% if e == 'Simple user' %}selected{% endif %}>{{ e }}</option>
|
||||
{% else %}
|
||||
<option value="{{ levels_users[e] }}" {% if useredit.level == levels_users[e] %}selected{% endif %}>{{ e }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td></tr>
|
||||
<tr><td> </td> <td><input id="submit" type="submit" value=" Entrer "></td></tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
25
templates/admin_users.html
Normal file
@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Administration {% endblock %}
|
||||
|
||||
{% block titre %}Administration : utilisateurs {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<fieldset class="fieldset" ><legend style="font-size:25px;">Ajouter un utilisateur</legend>
|
||||
<button id="add" onclick="javascript:go('/admin/users/new')">
|
||||
<img src="/static/plus.png" style="float:left;" alt=''/><div style="float:right; margin:5px;">Nouvel utilisateur</div>
|
||||
</button>
|
||||
</fieldset>
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Liste des utilisateurs</legend>
|
||||
<table width=100%>
|
||||
<thead>
|
||||
<tr><td>Login</td><td>Name</td><td>Level</td><td>Last login</td><td>Actions</td></tr>
|
||||
</thead>
|
||||
{% for u in users %}
|
||||
<tr><td>{{ u.login }}</td><td>{{ u.name }}</td><td>{{ u.level }}</td><td>{{ u.last_login }}</td><td><a href="/admin/users/{{ u.login }}"><img src="/static/edit.png" alt="Edit" /></a> <a href="/admin/users/{{ u.login }}/del"><img src="/static/croix.png" alt="Del" /></a></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
{% endblock %}
|
52
templates/base.html
Normal file
@ -0,0 +1,52 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
{% include ['head-perso.html', 'head.html'] %}
|
||||
{% block head %}
|
||||
<title>{% block title %}{% endblock %} - Belote</title>
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<div id="conteneur">
|
||||
<!-- ENTETE -->
|
||||
<div id="entete" class="clearfix-head">
|
||||
<div id="logo">
|
||||
<img src="/static/logo.gif" />
|
||||
</div><!-- logo -->
|
||||
<div id="titre">
|
||||
{% block titre %} {% endblock %}
|
||||
</div><!-- titre -->
|
||||
<div id="username">
|
||||
{% if not user == None %}
|
||||
{{ user.name }}
|
||||
{% else %}
|
||||
S'identifier
|
||||
{% endif %}
|
||||
<img id="username-fleche" src="/static/fleche-bas.gif"/>
|
||||
</div><!-- usernamev -->
|
||||
<div id="username-items">
|
||||
{% if not user == None %}
|
||||
<div id="username-item1" class="menu-item" onclick="javascript:go('/games')">Liste des jeux</div>
|
||||
<div id="username-item2" class="menu-item" onclick="javascript:go('/password')">Changer mon mot de passe</div>
|
||||
<div id="username-item3" class="menu-item" onclick="javascript:go('/logout')">Se déconnecter</div>
|
||||
{% if user.level > 9 %}
|
||||
<div id="username-item4" class="menu-item" onclick="javascript:go('/admin/games')">Admin des jeux</div>
|
||||
<div id="username-item5" class="menu-item" onclick="javascript:go('/admin/users')">Admin des utilisateurs</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div id="username-item1" class="menu-item" onclick="javascript:go('/login')">S'identifier</div>
|
||||
{% endif %}
|
||||
</div><!-- username-items-->
|
||||
</div><!-- entete -->
|
||||
|
||||
<!-- CONTENU -->
|
||||
{% block contenu %}
|
||||
{% endblock %}
|
||||
<!-- / CONTENU -->
|
||||
|
||||
</div>
|
||||
{% block script %} {% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
44
templates/belote.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!--
|
||||
La Belote
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<meta http-equiv="cache-control" content="no-cache" />
|
||||
<title>Belote</title>
|
||||
<!-- <link rel='stylesheet' type='text/css' href='./belote-reset.css' />-->
|
||||
<link rel='stylesheet' type='text/css' href='./belote-presentation.css' />
|
||||
<script src="./jquery-3.5.0.js"></script>
|
||||
<script src="./belote-script.js"></script>
|
||||
</head>
|
||||
<!----------------------
|
||||
BODY
|
||||
----------------------->
|
||||
<body>
|
||||
<div id="conteneur">
|
||||
<!----------------------
|
||||
ENTETE
|
||||
----------------------->
|
||||
<div id="entete" class="clearfix-head">
|
||||
<div id="logo">
|
||||
<img src="logo.gif" />
|
||||
</div><!-- logo -->
|
||||
<div id="titre">
|
||||
TITRE
|
||||
</div><!-- titre -->
|
||||
<div id="username">
|
||||
username
|
||||
<img id="username-fleche" src="./fleche-bas.gif"/>
|
||||
</div><!-- usernamev -->
|
||||
<div id="username-items">
|
||||
<div id="username-item1" class="menu-item">- item 1</div>
|
||||
<div id="username-item2" class="menu-item">- item 2</div>
|
||||
</div><!-- username-items-->
|
||||
</div><!-- entete -->
|
||||
<!----------------------
|
||||
ZONE-DE-JEU
|
||||
----------------------->
|
||||
/div><!-- conteneur -->
|
||||
</body>
|
||||
</html>
|
21
templates/game.html
Normal file
@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Jeu {% endblock %}
|
||||
|
||||
{% block titre %} Jeu {{ game.name }} {% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{% include ['scripts-perso.html', 'scripts.html'] %}
|
||||
{% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
{% include "game_zone_jeu.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var None = null;
|
||||
var jeu = {{ game.serialize_state(user)|safe }};
|
||||
</script>
|
||||
<script src="/static/game_script.js" charset="utf-8"></script>
|
||||
{% endblock %}
|
21
templates/game_add.html
Normal file
@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Créer jeu {% endblock %}
|
||||
|
||||
{% block titre %} Créer un jeu {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<div style="width:100%;margin:20px;"> </div>
|
||||
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Nom du jeu</legend>
|
||||
<form action="" method="POST" accept-charset="utf-8">
|
||||
Nom du jeu : <input type="text" name="name" id="name" />
|
||||
<input id="submit" type="submit" value="Créer">
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
17
templates/game_del.html
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Jeux {% endblock %}
|
||||
|
||||
{% block titre %} Suppression jeu {{game.name }} {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Confirmation</legend>
|
||||
<p>Sur de vouloir supprimer le jeu {{ game.name }} ? </p>
|
||||
<br />
|
||||
<table width=100% style="text-align:center">
|
||||
<tr><td><a href="?confirm=1">Oui</a></td><td> <a href="/games">Non</a></td></tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
{% endblock %}
|
166
templates/game_join.html
Normal file
@ -0,0 +1,166 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Jeu {% endblock %}
|
||||
|
||||
{% block titre %} Jeu {{game.name}} {% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{% include ['scripts-perso.html', 'scripts.html'] %}
|
||||
{% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<div style="width:100%;margin:20px;"> </div>
|
||||
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Liste des joueurs</legend>
|
||||
<ul id="players">
|
||||
{% for p in game.get_players() %}
|
||||
{% if p['username'] == admin %}
|
||||
<li id="player_{{ p['username'] }}"> {{ p['name'] }} ({{ p['username'] }}) (admin)</li>
|
||||
{% else %}
|
||||
{% if p['username'] == user.login %}
|
||||
<li id="player_{{ p['username'] }}"> {{ p['name'] }} ({{ p['username'] }}) <a href="javascript:leave()">(quitter le jeu)</a></li>
|
||||
{% elif user.login == admin %}
|
||||
<li id="player_{{ p['username'] }}"> {{ p['name'] }} ({{ p['username'] }}) <a href="javascript:ban('{{ p['username'] }}')">(bannir)</a></li>
|
||||
{% else %}
|
||||
<li id="player_{{ p['username'] }}"> {{ p['name'] }} ({{ p['username'] }})</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</fieldset>
|
||||
{% if user.login == admin %}
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Gestion des participants</legend>
|
||||
<form action="javascript:addplayer()">
|
||||
Ajouter par nom d'utilisateur :
|
||||
<input type="text" id="addplayer" />
|
||||
<input type="submit" value="Ajouter">
|
||||
</form>
|
||||
|
||||
<br />
|
||||
Vous pouvez aussi donner l'adresse du jeu (lire dans la barre d'adresse).
|
||||
</fieldset>
|
||||
<fieldset class="fieldset" id="gostart"><legend style="font-size:25px;">Démarrer le jeu</legend>
|
||||
<a href="javascript:gostart()">Commencer</a>
|
||||
</fieldset>
|
||||
{% else %}
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Info</legend>
|
||||
<p>Veuillez attendre que le maitre du jeu lance la partie...</p>
|
||||
<p>Rechargez la page si cela traine trop.</p>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var players = [
|
||||
{% for p in game.get_players() %}
|
||||
'{{ p['username'] }}',
|
||||
{% endfor %}
|
||||
];
|
||||
|
||||
{% if game.fixplayers %}
|
||||
var fix = true;
|
||||
{% else %}
|
||||
var fix = false;
|
||||
{% endif %}
|
||||
|
||||
{% if user.login == admin %}
|
||||
if (players.length < 4){
|
||||
$('#gostart').hide();
|
||||
}
|
||||
else{
|
||||
$('#add_player').hide();
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
var socket = io(window.location.pathname);
|
||||
|
||||
socket.on('connect', function() {
|
||||
socket.emit('join', {data: 'I\'m connected!'});
|
||||
});
|
||||
|
||||
socket.on('join', function(data){
|
||||
console.log('Join received', data['username'], data['name']);
|
||||
add_u(data['username'], data['name']);
|
||||
{% if user.login == admin %}
|
||||
if (players.length == 4){
|
||||
$('#gostart').show();
|
||||
$('#add_player').hide();
|
||||
}
|
||||
{% endif %}
|
||||
});
|
||||
|
||||
var add_u = function(username, name){
|
||||
if(players.indexOf(username)<0){
|
||||
players.push(username);
|
||||
html = `<li id="player_${username}"> ${name} (${username})`
|
||||
if(username == '{{ admin }}'){html+= ` (admin)`;}
|
||||
else if(username == '{{ user.login }}'){html+= ` <a href="javascript:leave()">(quitter le jeu)</a>`;}
|
||||
{% if user.login == admin -%}
|
||||
else{html+= ` <a href="javascript:ban('${username}')">(bannir)</a>`;}
|
||||
{%- endif %}
|
||||
html += `</li>`
|
||||
$('#players').append(html)
|
||||
fix_f();
|
||||
}
|
||||
}
|
||||
|
||||
socket.on('leave', function(data){
|
||||
console.log('Leave received', data['username']);
|
||||
username = data['username'];
|
||||
players.splice(players.indexOf(username), 1);
|
||||
$('#player_' + username).remove();
|
||||
|
||||
{% if user.login == admin %}
|
||||
$('#gostart').hide();
|
||||
$('#add_player').show();
|
||||
{% endif %}
|
||||
});
|
||||
|
||||
socket.on('fixplayers', function(data){
|
||||
fix = True;
|
||||
fix_f();
|
||||
});
|
||||
|
||||
var fix_f=function(){
|
||||
if(fix){
|
||||
$('#players li a').remove();
|
||||
{% if user.login == admin %}
|
||||
$('#add_player').hide();
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
fix_f();
|
||||
|
||||
socket.on('start', function(data){
|
||||
document.location.href="/game/{{ game.id }}";
|
||||
});
|
||||
|
||||
var leave = function(){
|
||||
socket.emit('leave', {});
|
||||
document.location.href ="/games";
|
||||
}
|
||||
|
||||
{% if user.login == admin %}
|
||||
var ban = function(username){
|
||||
socket.emit('ban', {'username': username});
|
||||
}
|
||||
|
||||
var gostart = function(){
|
||||
socket.emit('fixplayers', {});
|
||||
document.location.href="/game/{{ game.id }}/start";
|
||||
}
|
||||
|
||||
var addplayer = function(){
|
||||
username = $('#addplayer').val();
|
||||
if(username !=""){
|
||||
$('#addplayer').val('');
|
||||
socket.emit('add_player',{'username':username})
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock %}
|
88
templates/game_start.html
Normal file
@ -0,0 +1,88 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Jeu {% endblock %}
|
||||
|
||||
{% block titre %} Jeu {{ game.name }} {% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{% include ['scripts-perso.html', 'scripts.html'] %}
|
||||
{% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Liste des joueurs</legend>
|
||||
<p>Faites les équipes :</p>
|
||||
<ul id="players">
|
||||
</ul>
|
||||
</fieldset>
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Commencer</legend>
|
||||
<a href="javascript:gostart()">Commencer</a>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var players_order = [
|
||||
{% for p in game.get_players() %}
|
||||
'{{ p['username'] }}',
|
||||
{% endfor %}
|
||||
];
|
||||
var players = {
|
||||
{% for p in game.get_players() %}
|
||||
'{{ p['username'] }}': '{{ p['name'] }}',
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
var put_players = function(){
|
||||
var html = '';
|
||||
for(i=0;i<players_order.length;i++){
|
||||
html+= `<li> <div style="float:right"> <a href="javascript:up(${i})">Monter</a> <a href="javascript:down(${i})">Descendre</a></div> ${players[players_order[i]]} ( ${players_order[i]} ) <div style="clear:both"></div></li>`;
|
||||
}
|
||||
$('#players').html(html);
|
||||
}
|
||||
|
||||
put_players();
|
||||
|
||||
var up=function(i){
|
||||
t = players_order[i];
|
||||
if(i==0){
|
||||
n=players_order.length-1;
|
||||
}else{
|
||||
n = i-1;
|
||||
}
|
||||
players_order[i] = players_order[n]
|
||||
players_order[n] = t
|
||||
put_players();
|
||||
}
|
||||
|
||||
var down = function(i){
|
||||
t = players_order[i];
|
||||
if(i==players_order.length-1){
|
||||
n=0;
|
||||
}else{
|
||||
n = i+1;
|
||||
}
|
||||
players_order[i] = players_order[n]
|
||||
players_order[n] = t
|
||||
put_players();
|
||||
}
|
||||
|
||||
var socket = io('/game/{{ game.id }}/join');
|
||||
|
||||
socket.on('connect', function() {
|
||||
});
|
||||
|
||||
|
||||
socket.on('start', function(data){
|
||||
document.location.href="/game/{{ game.id }}";
|
||||
});
|
||||
|
||||
|
||||
var gostart = function(){
|
||||
socket.emit('start', {'order':players_order});
|
||||
document.location.href="/game/{{ game.id }}";
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
95
templates/game_zone_jeu.html
Normal file
@ -0,0 +1,95 @@
|
||||
<div id="zone-de-jeu">
|
||||
<div id="plateau">
|
||||
<div id="joueur-0" class="joueur">joueur 0</div><!-- joueur-0 -->
|
||||
<div id="joueur-1" class="joueur">joueur 1</div><!-- joueur-1 -->
|
||||
<div id="joueur-2" class="joueur">joueur 2</div><!-- joueur-2 -->
|
||||
<div id="joueur-3" class="joueur">joueur 3</div><!-- joueur-3 -->
|
||||
<div id="jeu-0" class="carte"></div><!-- jeu-0 -->
|
||||
<div id="jeu-1" class="carte"></div><!-- jeu-1 -->
|
||||
<div id="jeu-2" class="carte"></div><!-- jeu-2 -->
|
||||
<div id="jeu-3" class="carte"></div><!-- jeu-3 -->
|
||||
<form id="suivant">
|
||||
<input type="submit" name="suivant" value="Recommencer" onclick="javascript:restart_jeu()">
|
||||
</form><!-- suivant -->
|
||||
</div><!-- plateau -->
|
||||
<div id="ov">
|
||||
<table id="table-atout">
|
||||
<tr>
|
||||
<td>Atout</td>
|
||||
<td><div id="atout" class="carte"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="prispar">Pris par </td>
|
||||
<td id="preneur">----</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="choix">
|
||||
<div id="dernier-pli">
|
||||
<p class="item-choix">Dernier pli <img id="dernier-pli-fleche" src="/static/fleche-bas.gif" /></p>
|
||||
<div id="dernier-pli-valeur" class="item-choix-valeur clearfix">
|
||||
<div id="der-pli-0" class="carte carte-dernier-pli"></div>
|
||||
<div id="der-pli-1" class="carte carte-dernier-pli"></div>
|
||||
<div id="der-pli-2" class="carte carte-dernier-pli"></div>
|
||||
<div id="der-pli-3" class="carte carte-dernier-pli"></div>
|
||||
</div>
|
||||
</div><!-- dernier-pli -->
|
||||
<div id="options">
|
||||
<p class="item-choix">Options <img id="options-fleche" src="/static/fleche-bas.gif" /></p>
|
||||
<!--<div id="options-valeur" class="item-choix-valeur">Texte</div>-->
|
||||
</div><!-- options -->
|
||||
</div><!-- choix -->
|
||||
</div><!-- ov -->
|
||||
<div id="jeu-en-main" class="clearfix">
|
||||
<div id="a-vous">A vous de jouer !
|
||||
</div>
|
||||
<div id="carte-0" class="carte carte-en-main">
|
||||
</div>
|
||||
<div id="carte-1" class="carte carte-en-main">
|
||||
</div>
|
||||
<div id="carte-2" class="carte carte-en-main">
|
||||
</div>
|
||||
<div id="carte-3" class="carte carte-en-main">
|
||||
</div>
|
||||
<div id="carte-4" class="carte carte-en-main">
|
||||
</div>
|
||||
<div id="carte-5" class="carte carte-en-main">
|
||||
</div>
|
||||
<div id="carte-6" class="carte carte-en-main">
|
||||
</div>
|
||||
<div id="carte-7" class="carte carte-en-main">
|
||||
</div>
|
||||
</div><!-- jeu-en-main -->
|
||||
<div id="points">
|
||||
<p id="entete-points">Points
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Total</td>
|
||||
<td id="nopart">Partie</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nous</td>
|
||||
<td id="nous-tot">0</td>
|
||||
<td id="nous-part">0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Eux</td>
|
||||
<td id="eux-tot">0</td>
|
||||
<td id="eux-part">0</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><!-- points -->
|
||||
</div><!-- zone-de-jeu -->
|
||||
<!------------------------
|
||||
ZONE-DE-CONVERSATION
|
||||
------------------------->
|
||||
<div id="zone-de-conversation">
|
||||
<div id="chat">
|
||||
</div><!-- chat -->
|
||||
<div id="message">
|
||||
<p>Message</p>
|
||||
<input id="texte-msg" type="text" name="msg">
|
||||
<input type="submit" name="OK" value="OK" onclick="javascript:sendtext()">
|
||||
</div><!-- zone-message -->
|
||||
</div><!-- zone-de-conversation -->
|
43
templates/games.html
Normal file
@ -0,0 +1,43 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Jeux {% endblock %}
|
||||
|
||||
{% block titre %} Liste des jeux {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
{% if cancreategames %}
|
||||
<fieldset class="fieldset" ><legend style="font-size:25px;">Ajouter un jeu</legend>
|
||||
<button id="add" onclick="javascript:go('/add_game')">
|
||||
<img src="/static/plus.png" style="float:left;" alt=''/><div style="float:right; margin:5px;">Créer un nouveau jeu</div>
|
||||
</button>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if mesjeux|length > 0 %}
|
||||
<fieldset class="fieldset" ><legend style="font-size:25px;">Mes jeux</legend>
|
||||
<table class="tablelist">
|
||||
{% for g in mesjeux %}
|
||||
<tr>
|
||||
<td width=80%><a href="/game/{{g.id}}"> {{ g.name }} </a></td>
|
||||
<td width=20%><a href="/game/{{g.id}}"><img src="/static/ok.png" alt="Supprimer"/></a><a href="/game/{{g.id}}/del"><img src="/static/croix.png" alt="Supprimer"/></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
{% if joinable|length > 0 %}
|
||||
<fieldset class="fieldset" ><legend style="font-size:25px;">Autres jeux</legend>
|
||||
<table class="tablelist">
|
||||
{% for g in joinable %}
|
||||
<tr><td width=80%><a href="/game/{{g.id}}"> {{ g.name }} </a></td>
|
||||
<td width=20%><a href="/game/{{g.id}}"><img src="/static/ok.png" alt="Supprimer"/></a> </td>
|
||||
</tr>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
5
templates/head.html
Normal file
@ -0,0 +1,5 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<meta http-equiv="cache-control" content="no-cache" />
|
||||
<link rel='stylesheet' type='text/css' href='/static/belote.css' />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js" integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="/static/belote-script.js"></script>
|
12
templates/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Bienvenue {% endblock %}
|
||||
|
||||
{% block titre %} Bienvenue {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<p> Bienvenue sur le jeu de belote !</p>
|
||||
<p> Vous devez vous identifier pour jouer, rendez vous sur <a href="/login">la page de login</a></p>
|
||||
</div>
|
||||
{% endblock %}
|
29
templates/login.html
Normal file
@ -0,0 +1,29 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Login {% endblock %}
|
||||
|
||||
{% block titre %} Login {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<form method="POST" action="">
|
||||
<div style="width:100%;margin:20px;"> </div>
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Identifiez-vous</legend>
|
||||
{% for message in get_flashed_messages() %}
|
||||
<div class="alert alert-warning">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<table width=100%>
|
||||
<tr><td>Nom d'utilisateur : </td><td> <input type="text" name="username" placeholder="Votre nom d'utilisateur" /></td></tr>
|
||||
<tr><td> Mot de passe : </td><td> <input type="password" name="password" placeholder="Votre mot de passe"/></td></tr>
|
||||
<tr><td> </td> <td><input id="submit" type="submit" value=" Entrer "></td></tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
27
templates/password.html
Normal file
@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %} Mot de passe {% endblock %}
|
||||
|
||||
{% block titre %} Changement de mot de passe {% endblock %}
|
||||
|
||||
{% block contenu %}
|
||||
<div id="zone-de-contenu">
|
||||
<div style="width:100%;margin:20px;"> </div>
|
||||
|
||||
<fieldset class="fieldset"><legend style="font-size:25px;">Nom du jeu</legend>
|
||||
{% for message in get_flashed_messages() %}
|
||||
<div class="alert alert-warning">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<form action="" method="POST" accept-charset="utf-8">
|
||||
Nouveau mot de passe : <input type="password" name="password" />
|
||||
<input id="submit" type="submit" value="Valider">
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
1
templates/scripts.html
Normal file
@ -0,0 +1 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js" integrity="sha256-bQmrZe4yPnQrLTY+1gYylfNMBuGfnT/HKsCGX+9Xuqo=" crossorigin="anonymous"></script>
|