Merge pull request #136 from ThomasRubini/graphicalRefactor
Graphical refactor + other fix
@ -52,6 +52,16 @@ def get_npc_random_answer(npc_id:int, qa_type:int) -> Answer :
|
||||
answers = db.session.query(Answer).filter_by(QUESTION_TYPE_ID=qa_type,NPC_ID=npc_id.NPC_ID).all()
|
||||
return random.choice(answers)
|
||||
|
||||
def get_npc_from_npc_id(npc_id: int) -> Npc:
|
||||
"""
|
||||
Gets a Npc object from a npc_id
|
||||
|
||||
:param npc_id: the id of the trait to search for
|
||||
:return: a Npc object
|
||||
"""
|
||||
npc = db.session.query(Npc).filter_by(NPC_ID=npc_id).one()
|
||||
return npc
|
||||
|
||||
def get_random_question(qa_type: int) -> QuestionType :
|
||||
"""
|
||||
Returns a random inspector question from a question type
|
||||
@ -93,6 +103,18 @@ def get_reaction_description(lang, trait_id) -> str:
|
||||
desc_lid = db.session.query(Trait).filter_by(TRAIT_ID=trait_id).one().DESC_LID
|
||||
return get_text_from_lid(lang, desc_lid)
|
||||
|
||||
def get_reaction_from_npc_and_trait(npc_id: int,trait_id:int )-> Reaction:
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
npc_id (int): _description_
|
||||
trait_id (int): _description_
|
||||
|
||||
Returns:
|
||||
Reaction: _description_
|
||||
"""
|
||||
return db.session.query(Reaction).filter_by(NPC_ID=npc_id,TRAIT_ID=trait_id).one()
|
||||
|
||||
def get_traits(lang: str) -> list:
|
||||
"""
|
||||
Returns the list of all possible reactions trait in the given language
|
||||
@ -103,4 +125,15 @@ def get_traits(lang: str) -> list:
|
||||
traits = []
|
||||
for trait in db.session.query(Trait).all():
|
||||
traits.append(get_text_from_lid(lang,trait.NAME_LID))
|
||||
return traits
|
||||
return traits
|
||||
|
||||
def get_reaction_from_uuid(input_uuid: str) -> Reaction :
|
||||
"""_summary_ TODO
|
||||
|
||||
Args:
|
||||
input_uuid (str): _description_
|
||||
|
||||
Returns:
|
||||
Reaction: _description_
|
||||
"""
|
||||
return db.session.query(Reaction).filter_by(REACTION_UUID=input_uuid).one()
|
||||
|
@ -198,9 +198,9 @@ class Reaction(Base):
|
||||
NPC_ID = Column(Integer, ForeignKey("T_NPC.NPC_ID"), primary_key=True, comment="Name of the NPC that will have this reaction")
|
||||
TRAIT_ID = Column(Integer, ForeignKey("T_TRAIT.TRAIT_ID"), primary_key=True, comment="ID of the trait of this reaction")
|
||||
IMG = Column(LargeBinary(length=2**24), comment="Binary data of the image associated to this npc and trait")
|
||||
REACTION_UUID = Column(VARCHAR(255), unique=True, comment="ID of this reaction")
|
||||
NPC = relationship("Npc")
|
||||
TRAIT = relationship("Trait")
|
||||
REACTION_UUID = Column(VARCHAR(255), unique=True, comment="ID of this reaction")
|
||||
|
||||
def __init__(self, REACTION_ID, NPC_ID, TRAIT_ID):
|
||||
self.REACTION_ID = REACTION_ID
|
||||
|
@ -3,8 +3,6 @@ import time
|
||||
import random
|
||||
from typing import Union
|
||||
|
||||
from sqlalchemy import select, and_
|
||||
|
||||
from truthinquiry.ext.database.models import *
|
||||
from truthinquiry.ext.database.fsa import db
|
||||
from truthinquiry.ext.database import dbutils
|
||||
@ -90,6 +88,7 @@ class Game:
|
||||
trait_id = self.reaction_table[npc_id]
|
||||
trait = dbutils.get_trait_from_trait_id(trait_id)
|
||||
npcs[npc_id]["reaction"] = dbutils.get_text_from_lid("FR", trait.NAME_LID)
|
||||
npcs[npc_id]["uuid"] = dbutils.get_reaction_from_npc_and_trait(npc_id,self.reaction_table[npc_id]).REACTION_UUID
|
||||
npcs[npc_id]["description"] = dbutils.get_reaction_description("FR", trait.TRAIT_ID)
|
||||
player_results = data["player"] = {}
|
||||
for member in self.members:
|
||||
@ -140,11 +139,7 @@ class Game:
|
||||
if npc_id not in self.reaction_table:
|
||||
return None
|
||||
trait_id = self.reaction_table[npc_id]
|
||||
|
||||
reaction = db.session.execute(
|
||||
select(Reaction)
|
||||
.where(and_(Reaction.NPC_ID == int(npc_id), Reaction.TRAIT_ID == int(trait_id)))
|
||||
).one()[0]
|
||||
reaction = dbutils.get_reaction_from_npc_and_trait(npc_id,trait_id)
|
||||
return reaction.IMG
|
||||
|
||||
def get_player_results(self, responses: dict) -> Union[dict, None]:
|
||||
@ -347,5 +342,15 @@ def get_npc_image(npc_id: int):
|
||||
:param npc_id: npc to get the neutral image from
|
||||
:return: the byte representation of the image, none if its not found or not readable
|
||||
"""
|
||||
npc = db.session.execute(select(Npc).where(Npc.NPC_ID==npc_id)).one()[0]
|
||||
npc = dbutils.get_npc_from_npc_id(npc_id)
|
||||
return npc.DEFAULT_IMG
|
||||
|
||||
def get_reactions_image_from_uuid(uuid: str):
|
||||
"""
|
||||
Returns the byte representation of the neutral image for an npc
|
||||
|
||||
:param npc_id: npc to get the neutral image from
|
||||
:return: the byte representation of the image, none if its not found or not readable
|
||||
"""
|
||||
reaction = dbutils.get_reaction_from_uuid(uuid)
|
||||
return reaction.IMG
|
||||
|
@ -85,12 +85,16 @@ def join_game():
|
||||
|
||||
if not game.add_member(username):
|
||||
return {"error": 1, "msg": f"Username '{username}' already used in game {game.game_id}"}
|
||||
|
||||
if game.has_started:
|
||||
return {"error": 1, "msg": f"Game {game.game_id} has already started"}
|
||||
|
||||
|
||||
flask.session["game_id"] = game.game_id
|
||||
flask.session["is_owner"] = False
|
||||
flask.session["username"] = username
|
||||
|
||||
socket_io.emit("playersjoin", [flask.session["username"]], room="game."+game.game_id)
|
||||
socket_io.emit("playersjoin", flask.session["username"], room="game."+game.game_id)
|
||||
|
||||
return {"error": 0}
|
||||
|
||||
@ -199,14 +203,11 @@ def get_npc_reaction():
|
||||
@routes_api.route("/getReaction", methods=["GET", "POST"])
|
||||
def get_reaction():
|
||||
input_uuid = flask.request.values.get("uuid")
|
||||
results = db.session.execute(select(Reaction).where(Reaction.REACTION_UUID==input_uuid))
|
||||
|
||||
row = results.first()
|
||||
if row == None:
|
||||
image = game_logic.get_reactions_image_from_uuid(input_uuid)
|
||||
if image is None:
|
||||
return {"error": 1, "msg": "No such reaction"}
|
||||
reaction_obj = row[0]
|
||||
|
||||
return flask.send_file(io.BytesIO(reaction_obj.IMG), mimetype='image/png')
|
||||
return flask.send_file(io.BytesIO(image), mimetype='image/png')
|
||||
|
||||
|
||||
|
||||
@ -230,6 +231,24 @@ def game_progress():
|
||||
|
||||
return {"error": 0}
|
||||
|
||||
@routes_api.route("/chatMessage", methods=["GET", "POST"])
|
||||
def chat_message():
|
||||
if not flask.session:
|
||||
return {"error": 1, "msg": "No session"}
|
||||
game_id = flask.session["game_id"]
|
||||
if not game_logic.check_game_id(game_id):
|
||||
return {"error": 1, "msg": "invalid game_id"}
|
||||
game = game_logic.get_game(game_id)
|
||||
if game is None:
|
||||
return {"error": 1, "msg": "this game doesn't exist"}
|
||||
|
||||
username = flask.session["username"]
|
||||
message_received = flask.request.values.get("msg")
|
||||
|
||||
message_sent = f"{username} : {message_received}"
|
||||
socket_io.emit("chatMessage", message_sent, room="game."+game.game_id)
|
||||
|
||||
return {"error": 0}
|
||||
|
||||
@routes_api.route("/submitAnswers", methods=["GET", "POST"])
|
||||
def check_anwser():
|
||||
|
@ -17,6 +17,23 @@
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Park Lane";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url("../fonts/park_lane/parklane.regular.otf") format('otf'), url("../fonts/park_lane/parklane.regular.ttf") format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Ironick";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url("../fonts/ironick_nf/IronickNF.otf") format('otf'), url("../fonts/ironick_nf/IronickNF.ttf") format('truetype');
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: "Roboto Mono";
|
||||
@ -31,12 +48,14 @@
|
||||
/* Colors */
|
||||
color-scheme: dark;
|
||||
--alert-dialog-background-color: #000000DF;
|
||||
--dark-theme-background-color: #213C40;
|
||||
--dark-theme-background-color: #0c0b0c;
|
||||
--game-black: #000000;
|
||||
--game-blue: #7DDCFF;
|
||||
--game-green: #008000;
|
||||
--game-grey: #5A5656;
|
||||
--game-red: #BD1E1E;
|
||||
--game-gold: rgb(214,168,81);
|
||||
--game-dark-gold: #B9935A;
|
||||
--game-white: #FFFFFF;
|
||||
--light-theme-background-color: #B1EDE8;
|
||||
/* Sizes */
|
||||
@ -58,7 +77,7 @@ noscript .alert_dialog_background, noscript .alert_dialog_msg, noscript .alert_d
|
||||
}
|
||||
|
||||
.action_button {
|
||||
background-color: var(--game-red);
|
||||
background-color: var(--game-dark-gold);
|
||||
border-color: var(--game-black);
|
||||
border-radius: var(--button-and-dialog-border-radius);
|
||||
border-style: solid;
|
||||
@ -89,8 +108,14 @@ noscript .alert_dialog_background, noscript .alert_dialog_msg, noscript .alert_d
|
||||
/* Utility classes */
|
||||
.hidden {
|
||||
display: none !important;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.gray {
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
|
||||
/* Links */
|
||||
.link {
|
||||
text-decoration: none;
|
||||
|
@ -12,8 +12,8 @@ html {
|
||||
font-family: "Titan One", sans-serif;
|
||||
}
|
||||
|
||||
.anwser_title, .emotion_and_culprit_choices_title, .introduction_text, .introduction_title, .interrogation_title, .results_title, .reveal_culprit_title, .score_title, .summary_title {
|
||||
font-family: "Spicy Rice", serif;
|
||||
.anwser_title, .emotion_and_culprit_choices_title, .introduction_text, .introduction_title, .interrogation_title, .results_title,.introduction_right ,.reveal_culprit_title, .score_title, .summary_title {
|
||||
font-family: "Ironick", serif;
|
||||
}
|
||||
|
||||
.culprit_btn, .interrogation, .player_score, .question_answer, .questions_and_image, .reveal_culprit, .reveal_score, .scores, .summary, .summary_suspect, .suspect_picture[alt], .suspect, .suspects, .suspects_list {
|
||||
@ -50,7 +50,7 @@ html {
|
||||
}
|
||||
|
||||
.emotion_and_culprit_choices_title, .interrogation_title, .introduction_title, .results_title, .reveal_culprit_title, .reveal_score, .score_title, .summary_title {
|
||||
color: var(--game-red);
|
||||
color: var(--game-gold);
|
||||
}
|
||||
|
||||
.emotion_and_culprit_choices_title, .results_title, .reveal_culprit_title, .score_title, .summary, .summary_title, .suspect_picture[alt] {
|
||||
@ -110,8 +110,33 @@ html {
|
||||
}
|
||||
|
||||
.suspect_picture {
|
||||
border: var(--game-dark-gold) solid 5px;
|
||||
border-radius: 1em;
|
||||
height: 15em;
|
||||
width: 15em;
|
||||
transition: all 0.5s ease;
|
||||
|
||||
}
|
||||
.npc_answer{
|
||||
flex-direction: column;
|
||||
width: 40em;
|
||||
}
|
||||
.image_interrogation{
|
||||
height: 25em;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.question_answer{
|
||||
border: var(--game-dark-gold) solid;
|
||||
border-radius: 1em;
|
||||
height: 6em;
|
||||
background-color: #000000d0;
|
||||
}
|
||||
|
||||
.suspect > .suspect_picture:hover {
|
||||
filter: grayscale(0);
|
||||
transition: all 0.5s ease;
|
||||
background-color: #000000d0;
|
||||
}
|
||||
|
||||
.suspect_picture[alt] {
|
||||
@ -124,7 +149,7 @@ html {
|
||||
}
|
||||
|
||||
.home_button, .next_btn {
|
||||
fill: var(--game-red);
|
||||
fill: var(--game-dark-gold);
|
||||
height: 5em;
|
||||
width: 5em;
|
||||
}
|
||||
@ -151,12 +176,21 @@ html {
|
||||
|
||||
/* Introduction */
|
||||
.introduction {
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.introduction_left{
|
||||
padding: 1em;
|
||||
max-width: 50vw;
|
||||
}
|
||||
|
||||
.introduction_text {
|
||||
.introduction_right{
|
||||
font-size: 2em;
|
||||
padding: 1em;
|
||||
max-width: 50vw;
|
||||
}
|
||||
.introduction_text {
|
||||
font-size: 3em;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
@ -166,13 +200,25 @@ html {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.inspector_picture{
|
||||
border: var(--game-dark-gold) solid 5px;
|
||||
border-radius: 1em;
|
||||
max-width: 45vw;
|
||||
background-color: #000000d0;
|
||||
}
|
||||
|
||||
.username{
|
||||
font-size: 3em;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/* Interrogation */
|
||||
.ask_button {
|
||||
background-color: var(--game-white);
|
||||
background-color: var(--game-dark-gold);
|
||||
color: var(--game-black);
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.anwser_title {
|
||||
font-size: 2.5em;
|
||||
margin: 0.25em;
|
||||
@ -194,6 +240,16 @@ html {
|
||||
#interrogation_suspect_previous_btn {
|
||||
margin-right: 1em;
|
||||
}
|
||||
.suspect_name{
|
||||
font-family: "Park Lane";
|
||||
font-size: 2em;
|
||||
color: var(--game-dark-gold);
|
||||
border-radius: 0.25em;
|
||||
margin: 0;
|
||||
border: var(--game-dark-gold) solid 1px;
|
||||
padding: 0.25em;
|
||||
background-color: #000000dd;
|
||||
}
|
||||
|
||||
/* Emotion and culprit choices */
|
||||
.culprit_icon {
|
||||
@ -203,6 +259,7 @@ html {
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
|
||||
.culprit_btn_checked {
|
||||
background-color: var(--game-green);
|
||||
}
|
||||
@ -235,6 +292,13 @@ html {
|
||||
}
|
||||
|
||||
/* Results and scores */
|
||||
.explain {
|
||||
border: var(--game-dark-gold) solid;
|
||||
border-radius: 1em;
|
||||
background-color: #000000d0;
|
||||
}
|
||||
|
||||
|
||||
.explain_suspect_emotion_description {
|
||||
font-size: 1.25em;
|
||||
font-weight: normal;
|
||||
@ -283,3 +347,87 @@ html {
|
||||
#return_lobby_button {
|
||||
border: transparent;
|
||||
}
|
||||
|
||||
* {box-sizing: border-box;}
|
||||
|
||||
/* chat */
|
||||
/* Button used to open the chat form - fixed at the bottom of the page */
|
||||
.open-button {
|
||||
background-color: #000000dd;
|
||||
color: var(--game-dark-gold);
|
||||
padding: 16px 20px;
|
||||
border: var(--game-dark-gold) solid;
|
||||
border-radius: 1em;
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
position: fixed;
|
||||
bottom: 23px;
|
||||
right: 28px;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
/* The popup chat - hidden by default */
|
||||
.chat-popup {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
color: var(--game-dark-gold);
|
||||
right: 15px;
|
||||
z-index: 9;
|
||||
border: solid black 1px;
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
/* Add styles to the form container */
|
||||
.form-container {
|
||||
max-width: 300px;
|
||||
padding: 10px;
|
||||
border: solid var(--game-dark-gold);
|
||||
border-radius: 1em;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
/* Full-width textarea */
|
||||
.form-container textarea {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin: 5px 0 22px 0;
|
||||
border: none;
|
||||
background: #f1f1f1;
|
||||
resize: none;
|
||||
min-height: 5em;
|
||||
}
|
||||
|
||||
/* When the textarea gets focus, do something */
|
||||
#chat_message_box{
|
||||
background-color: #505050;
|
||||
outline: none;
|
||||
margin: 10px;
|
||||
}
|
||||
.message{
|
||||
list-style-type: none
|
||||
}
|
||||
/* Set a style for the submit/send button */
|
||||
.form-container .btn {
|
||||
background-color: black;
|
||||
color: #04AA6D;
|
||||
padding: 16px 20px;
|
||||
border: #04AA6D solid;
|
||||
border-radius: 1em;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
margin-bottom:10px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Add a red background color to the cancel button */
|
||||
.form-container .cancel {
|
||||
background-color: black;
|
||||
color: red;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
/* Add some hover effects to buttons */
|
||||
.form-container .btn:hover, .open-button:hover {
|
||||
opacity: 1;
|
||||
}
|
@ -3,6 +3,18 @@ html {
|
||||
background-color: var(--game-black);
|
||||
color: var(--game-white);
|
||||
}
|
||||
.current_background {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
filter: blur(4px);
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
/* Place the background behind everything */
|
||||
z-index: -9999;
|
||||
}
|
||||
|
||||
.action_button, .multi_player_mode_choice_title, .multi_player_mode_waiting_for_host, .player_name, .players_title, .rounds_count_title, .room_code_text_title, .room_title, #game_username, #rounds_count {
|
||||
font-family: "Titan One", sans-serif;
|
||||
@ -13,7 +25,7 @@ html {
|
||||
}
|
||||
|
||||
.game_start_failed, .multi_player_challenge_mode_invalid_input, .room_code, .room_title {
|
||||
color: var(--game-red);
|
||||
color: var(--game-dark-gold);
|
||||
}
|
||||
|
||||
.join_room_view, .multi_player_mode_choice, .multi_player_mode_choice_number, .players_title, .room_code_text, .room_view_container {
|
||||
@ -133,6 +145,9 @@ html {
|
||||
|
||||
.multi_player_mode_choices {
|
||||
padding: 1em;
|
||||
border: var(--game-dark-gold) solid;
|
||||
border-radius: 1em;
|
||||
background-color: #000000d0;
|
||||
}
|
||||
|
||||
/* Rounds count */
|
||||
@ -163,7 +178,6 @@ html {
|
||||
border-radius: 0.75em;
|
||||
font-size: 1.25em;
|
||||
max-height: 12em;
|
||||
min-width: 25em;
|
||||
overflow-y: scroll;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
@ -50,14 +50,15 @@ input::placeholder {
|
||||
}
|
||||
|
||||
.back_btn {
|
||||
fill: var(--game-red);
|
||||
fill: var(--game-dark-gold);
|
||||
}
|
||||
|
||||
.game_begin {
|
||||
background-image: url("../images/start_background.png");
|
||||
background-image: url("../images/start_background.jpg");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
border: var(--game-gold) solid 1px;
|
||||
border-radius: 1.5em;
|
||||
flex-wrap: wrap;
|
||||
/*
|
||||
@ -66,15 +67,14 @@ input::placeholder {
|
||||
*/
|
||||
height: calc(100vh - var(--body-margin) * 2
|
||||
- var(--game-begin-margin) * 2
|
||||
- var(--header-actions-side)
|
||||
- var(--footer-links-height));
|
||||
justify-content: center;
|
||||
margin: var(--game-begin-margin);
|
||||
}
|
||||
|
||||
.game_title {
|
||||
color: var(--game-red);
|
||||
font-family: "Spicy Rice", serif;
|
||||
color: var(--game-gold);
|
||||
font-family: "Ironick", serif;
|
||||
font-size: 5em;
|
||||
font-weight: bold;
|
||||
margin: 0.25em;
|
||||
@ -109,7 +109,7 @@ input::placeholder {
|
||||
}
|
||||
|
||||
.game_mode_selection {
|
||||
background-image: url("../images/start_background.png");
|
||||
background-image: url("../images/start_background.jpg");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@ -133,10 +133,6 @@ input::placeholder {
|
||||
}
|
||||
|
||||
.game_mode_choice_selector {
|
||||
background-color: var(--game-black);
|
||||
border-color: var(--game-white);
|
||||
border-style: solid;
|
||||
border-radius: 1.5em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
|
BIN
truthinquiry/static/fonts/ironick_nf/IronickNF.otf
Normal file
BIN
truthinquiry/static/fonts/ironick_nf/IronickNF.ttf
Normal file
BIN
truthinquiry/static/fonts/park_lane/parklane.regular.otf
Normal file
BIN
truthinquiry/static/fonts/park_lane/parklane.regular.ttf
Normal file
BIN
truthinquiry/static/images/cuisine.jpg
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
truthinquiry/static/images/entrée-manoir.jpg
Normal file
After Width: | Height: | Size: 998 KiB |
BIN
truthinquiry/static/images/entrée-manoir.jpg
Normal file
After Width: | Height: | Size: 331 KiB |
BIN
truthinquiry/static/images/inspector.png
Normal file
After Width: | Height: | Size: 400 KiB |
BIN
truthinquiry/static/images/png_original/cuisine.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 4.2 MiB After Width: | Height: | Size: 4.2 MiB |
BIN
truthinquiry/static/images/png_original/entrée-manoir.png
Normal file
After Width: | Height: | Size: 4.2 MiB |
Before Width: | Height: | Size: 5.7 MiB After Width: | Height: | Size: 5.7 MiB |
Before Width: | Height: | Size: 5.8 MiB After Width: | Height: | Size: 5.8 MiB |
Before Width: | Height: | Size: 602 KiB After Width: | Height: | Size: 602 KiB |
BIN
truthinquiry/static/images/salle-interrogation.jpg
Normal file
After Width: | Height: | Size: 478 KiB |
BIN
truthinquiry/static/images/salle-resultats.jpg
Normal file
After Width: | Height: | Size: 500 KiB |
BIN
truthinquiry/static/images/start_background.jpg
Normal file
After Width: | Height: | Size: 1.0 MiB |
@ -1,8 +1,9 @@
|
||||
const INTRO_IMAGE_PATH = "/static/images/entrée-manoir.png";
|
||||
const INTERROGATION_IMAGE_PATH = "/static/images/salle-interrogation.png";
|
||||
const RESULTS_IMAGE_PATH = "/static/images/salle-resultats.png";
|
||||
const INTRO_IMAGE_PATH = "/static/images/entrée-manoir.jpg";
|
||||
const INTERROGATION_IMAGE_PATH = "/static/images/salle-interrogation.jpg";
|
||||
const RESULTS_IMAGE_PATH = "/static/images/salle-resultats.jpg";
|
||||
const NPC_REACTION_PATH = "/api/v1/getNpcReaction?npcid=";
|
||||
const NPC_IMAGE_PATH = "/api/v1/getNpcImage?npcid=";
|
||||
const NPC_FINAL_REACTION_PATH = "/api/v1/getReaction?uuid="
|
||||
|
||||
let npcsIds = [];
|
||||
let gameData = {};
|
||||
@ -48,6 +49,32 @@ function unsetQuestionButtonsListeners() {
|
||||
.removeEventListener("click", askTypeOneQuestion);
|
||||
}
|
||||
|
||||
function setChatBoxButtonsListeners() {
|
||||
document.getElementById("close_chat_button")
|
||||
.addEventListener("click", closeForm);
|
||||
document.getElementById("open_chat_button")
|
||||
.addEventListener("click", openForm);
|
||||
document.getElementById("chat_button_send")
|
||||
.addEventListener("click", sendChatMessage);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows the chat box
|
||||
*/
|
||||
function openForm() {
|
||||
document.getElementById("chatbox").style.display = "block";
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the chat box
|
||||
*/
|
||||
function closeForm() {
|
||||
document.getElementById("chatbox").style.display = "none";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Go back to interrogation view, by hiding the interrogation suspect view.
|
||||
*/
|
||||
@ -179,7 +206,7 @@ async function askQuestion(buildAnswer) {
|
||||
document.querySelector(".suspect_answer").textContent = buildAnswer(
|
||||
getNpcLocationAndPartner(currentNpc));
|
||||
|
||||
showFirstClassElement("question_answer");
|
||||
showFirstClassElement("suspect_answer");
|
||||
|
||||
document.getElementById("currentNpcPicure").src = NPC_REACTION_PATH + currentNpc;
|
||||
|
||||
@ -188,7 +215,7 @@ async function askQuestion(buildAnswer) {
|
||||
await new Promise(r => setTimeout(r, 4000));
|
||||
|
||||
document.getElementById("currentNpcPicure").src = NPC_IMAGE_PATH + currentNpc;
|
||||
hideFirstClassElement("question_answer");
|
||||
hideFirstClassElement("suspect_answer");
|
||||
|
||||
document.querySelector(".suspect_answer").textContent = "";
|
||||
|
||||
@ -291,19 +318,35 @@ function createCulpritSvgElement(buttonCssClass, pathAttributeValue, isHidden) {
|
||||
* Show the screen in which the player asks questions to the npcs.
|
||||
*/
|
||||
function renderInterrogation() {
|
||||
if (gameData["solo"] === true) document.getElementById("open_chat_button").classList.add("hidden");
|
||||
|
||||
document.getElementById("QA_0").textContent = gameData["questions"]["QA_0"];
|
||||
document.getElementById("QA_1").textContent = gameData["questions"]["QA_1"];
|
||||
|
||||
const interrogationSuspects = document.getElementById("interrogation_suspects");
|
||||
|
||||
npcsIds.forEach(element => {
|
||||
npcsIds.forEach(npc_id => {
|
||||
const suspect = document.createElement("li");
|
||||
suspect.classList.add("suspect");
|
||||
|
||||
const name = document.createElement('p')
|
||||
name.textContent = gameData['npcs'][npc_id]["name"]
|
||||
name.classList.add("suspect_name");
|
||||
suspect.appendChild(name);
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.id = "suspect_picture_of_" + npc_id
|
||||
img.classList.add("suspect_picture");
|
||||
img.setAttribute("alt", "Image d'un suspect");
|
||||
img.src = NPC_IMAGE_PATH + element;
|
||||
img.src = NPC_IMAGE_PATH + npc_id;
|
||||
img.addEventListener("click", () => {
|
||||
// TODO remove this listener when we know the questions has already been asked;
|
||||
currentNpc = npc_id;
|
||||
document.getElementById("suspect_picture_of_" + npc_id).classList.add("gray");
|
||||
document.getElementById("currentNpcPicure").src = NPC_IMAGE_PATH + npc_id;
|
||||
hideFirstClassElement("interrogation");
|
||||
showFirstClassElement("interrogation_suspect");
|
||||
});
|
||||
suspect.appendChild(img);
|
||||
|
||||
const button = document.createElement("button");
|
||||
@ -311,17 +354,29 @@ function renderInterrogation() {
|
||||
button.textContent = "Interroger";
|
||||
button.addEventListener("click", () => {
|
||||
// TODO remove this listener when we know the questions has already been asked;
|
||||
currentNpc = element;
|
||||
document.getElementById("currentNpcPicure").src = NPC_IMAGE_PATH + element;
|
||||
currentNpc = npc_id;
|
||||
document.getElementById("suspect_picture_of_" + npc_id).classList.add("gray");
|
||||
document.getElementById("currentNpcPicure").src = NPC_IMAGE_PATH + npc_id;
|
||||
hideFirstClassElement("interrogation");
|
||||
showFirstClassElement("interrogation_suspect");
|
||||
});
|
||||
|
||||
suspect.appendChild(button);
|
||||
interrogationSuspects.appendChild(suspect);
|
||||
});
|
||||
}
|
||||
|
||||
function sendChatMessage(){
|
||||
const message = document.getElementById("chat_message_box").value;
|
||||
const data = {};
|
||||
data["msg"] = message;
|
||||
makeAPIRequest("chatMessage",data);
|
||||
document.getElementById("chat_message_box").value = '';
|
||||
}
|
||||
|
||||
function renderIntroduction(){
|
||||
document.getElementById("username").textContent += username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the websocket for this page, its primary use is to show the final page once it
|
||||
* receives the event that all players have finished.
|
||||
@ -346,8 +401,16 @@ function initSock() {
|
||||
socket.on("gameprogress", username => {
|
||||
console.log(username);
|
||||
});
|
||||
|
||||
socket.on("chatMessage", message => {
|
||||
const message_received = document.createElement("li");
|
||||
message_received.classList.add("message");
|
||||
message_received.textContent = message;
|
||||
document.getElementById("message_list").appendChild(message_received);
|
||||
});
|
||||
|
||||
socket.on("gamefinished", finalResults => {
|
||||
console.log(finalResults);
|
||||
hideFirstClassElement("emotion_and_culprit_choices");
|
||||
const revealScoreElement = document.createElement("h2");
|
||||
revealScoreElement.classList.add("reveal_score");
|
||||
@ -398,22 +461,25 @@ function initSock() {
|
||||
|
||||
const img = document.createElement("img");
|
||||
img.setAttribute("alt", "Image d'un suspect");
|
||||
img.src = NPC_IMAGE_PATH + npcid;
|
||||
img.src = NPC_FINAL_REACTION_PATH + finalResults["npcs"][npcid]["uuid"];
|
||||
suspect.appendChild(img);
|
||||
|
||||
const explain = document.createElement("div")
|
||||
explain.classList.add("explain")
|
||||
|
||||
const emotionTitle = document.createElement("h2");
|
||||
emotionTitle.classList.add("explain_suspect_emotion_title");
|
||||
emotionTitle.textContent = "Ce suspect était "
|
||||
+ finalResults["npcs"][npcid]["reaction"] + ".";
|
||||
|
||||
suspect.appendChild(emotionTitle);
|
||||
|
||||
|
||||
explain.appendChild(emotionTitle);
|
||||
|
||||
const emotionDesc = document.createElement("p");
|
||||
emotionDesc.classList.add("explain_suspect_emotion_description");
|
||||
emotionDesc.textContent = "Cette émotion se caractérise par "
|
||||
+ finalResults["npcs"][npcid]["description"];
|
||||
suspect.appendChild(emotionDesc);
|
||||
|
||||
explain.appendChild(emotionDesc);
|
||||
suspect.appendChild(explain)
|
||||
suspectListElement.appendChild(suspect);
|
||||
});
|
||||
});
|
||||
@ -439,10 +505,12 @@ async function setGameData() {
|
||||
async function initGame() {
|
||||
await setGameData();
|
||||
initSock();
|
||||
renderIntroduction();
|
||||
renderAnswerSelectionPanel();
|
||||
renderInterrogation();
|
||||
setQuestionButtonsListeners()
|
||||
setIntroductionAndInterrogationListeners();
|
||||
setChatBoxButtonsListeners();
|
||||
showFirstClassElement("introduction");
|
||||
setGameBackground(INTRO_IMAGE_PATH);
|
||||
}
|
||||
|
@ -1,5 +1,13 @@
|
||||
const LOBBY_IMAGE_PATH = "/static/images/cuisine.jpg"
|
||||
// Display functions
|
||||
|
||||
/*
|
||||
* Set the current game background to the first element with the current_background CSS class.
|
||||
*/
|
||||
function setGameBackground(backgroundPath) {
|
||||
document.querySelector(".current_background").style.backgroundImage = 'url("' + backgroundPath + '")';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the invalid rounds count message element, by removing the hidden CSS class.
|
||||
*
|
||||
@ -129,7 +137,6 @@ function joinRoom() {
|
||||
response.then(() => {
|
||||
displayRoomView();
|
||||
displayPlayerList();
|
||||
initSock();
|
||||
hideFirstClassElement("join_room_view");
|
||||
})
|
||||
}
|
||||
@ -348,13 +355,15 @@ function initSock() {
|
||||
console.log("Connected to the server!");
|
||||
})
|
||||
|
||||
socket.on("gamestart", () => {
|
||||
window.location.href = "/multi";
|
||||
socket.on("gamestart", async () => {
|
||||
if (await hasJoinedRoom()) window.location.href = "/multi";
|
||||
})
|
||||
|
||||
socket.on("playersjoin", username => {
|
||||
document.querySelector(".player_names")
|
||||
.appendChild(document.createTextNode(username + "\n"));
|
||||
console.log(username);
|
||||
Array.from(document.getElementsByClassName("player_names")).forEach(playerList =>{
|
||||
playerList.textContent += username + "\n";
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@ -375,9 +384,10 @@ function initSock() {
|
||||
* </p>
|
||||
*/
|
||||
async function initLobby() {
|
||||
setGameBackground(LOBBY_IMAGE_PATH)
|
||||
getMembers()
|
||||
initSock();
|
||||
if (await hasJoinedRoom()) {
|
||||
initSock();
|
||||
displayRoomView();
|
||||
|
||||
if (await isRoomOwner()) {
|
||||
|
@ -281,4 +281,4 @@ document.getElementById("join_room_button").addEventListener("click", joinMultiP
|
||||
|
||||
// Execution of functions
|
||||
|
||||
setCurrentTheme();
|
||||
//setCurrentTheme();
|
||||
|
@ -18,13 +18,19 @@
|
||||
<body class="game_app">
|
||||
<div class="current_background"></div>
|
||||
<section class="introduction hidden">
|
||||
<h1 class="introduction_title">Truth Inquiry</h1>
|
||||
<p class="introduction_text">Bienvenue dans Truth Inquiry, vous allez intégrer la peau d’un enquêteur.<br><br>Vous avez été donné responsable de résoudre une enquête et devez trouver le coupable d’un vol.<br><br>Cliquez sur la flèche pour découvrir les suspects et les interroger.</p>
|
||||
<button id="introduction_next_btn" class="next_btn" aria-label="Commencer" title="Cliquez ici pour commencer à jouer">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
|
||||
<path d="m23.15 36.95-17.3-11.1Q4.7 25.25 4.7 24t1.15-1.9L23.15 11q1.15-.7 2.35-.075 1.2.625 1.2 2.025v8.75h15.8q.95 0 1.625.675T44.8 24q0 .95-.675 1.6-.675.65-1.625.65H26.7V35q0 1.45-1.2 2.075-1.2.625-2.35-.125Z" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="introduction_left">
|
||||
<h1 class="introduction_title">Truth Inquiry</h1>
|
||||
<p class="introduction_text">Bienvenue dans Truth Inquiry, vous allez intégrer la peau d’un enquêteur.<br><br>Vous avez été donné responsable de résoudre une enquête et devez trouver le coupable d’un vol.<br><br>Cliquez sur la flèche pour découvrir les suspects et les interroger.</p>
|
||||
<button id="introduction_next_btn" class="next_btn" aria-label="Commencer" title="Cliquez ici pour commencer à jouer">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
|
||||
<path d="m23.15 36.95-17.3-11.1Q4.7 25.25 4.7 24t1.15-1.9L23.15 11q1.15-.7 2.35-.075 1.2.625 1.2 2.025v8.75h15.8q.95 0 1.625.675T44.8 24q0 .95-.675 1.6-.675.65-1.625.65H26.7V35q0 1.45-1.2 2.075-1.2.625-2.35-.125Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="introduction_right">
|
||||
<p id="username">Le celebre inspecteur : </p>
|
||||
<img class="inspector_picture" src="/static/images/inspector.png" alt="Image de l'inspecteur">
|
||||
</div>
|
||||
</section>
|
||||
<section class="interrogation hidden">
|
||||
<h1 class="interrogation_title">Suspects</h1>
|
||||
@ -34,6 +40,23 @@
|
||||
</svg>
|
||||
</button>
|
||||
<ul class="suspects" id="interrogation_suspects"></ul>
|
||||
<Section>
|
||||
<button id="open_chat_button" class="open-button">Chat</button>
|
||||
<div class="chat-popup" id="chatbox">
|
||||
<div class="form-container">
|
||||
<h1>Chat</h1>
|
||||
<div class="messages_received_container">
|
||||
<ul id="message_list" class="messages">
|
||||
</ul>
|
||||
</div>
|
||||
<label for="msg"><b>Message</b></label>
|
||||
<input type="text" id="chat_message_box" placeholder="Type message.." name="msg" required></textarea>
|
||||
|
||||
<button id="chat_button_send" class="btn">Send</button>
|
||||
<button id="close_chat_button" type="button" class="btn cancel">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
</section>
|
||||
<section class="emotion_and_culprit_choices hidden">
|
||||
<h1 class="emotion_and_culprit_choices_title">Choix du coupable et émotion des suspects</h1>
|
||||
@ -53,14 +76,16 @@
|
||||
</svg>
|
||||
</button>
|
||||
<img class="image_interrogation suspect_picture" id="currentNpcPicure" alt="Image du suspect en cours d'interrogation" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==">
|
||||
<div class="questions_list">
|
||||
<button class="action_button question_button" id="QA_0">Où étiez vous hier soir ?</button>
|
||||
<button class="action_button question_button" id="QA_1">Avec qui étiez vous ?</button>
|
||||
<div class ="npc_answer">
|
||||
<h1 class="anwser_title">Réponse du suspect à la question</h1>
|
||||
<div class="question_answer">
|
||||
<p class="suspect_answer"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question_answer hidden">
|
||||
<h1 class="anwser_title">Réponse du suspect à la question</h1>
|
||||
<p class="suspect_answer"></p>
|
||||
<div class="questions_list">
|
||||
<button class="action_button question_button" id="QA_0">Où étiez vous hier soir ?</button>
|
||||
<button class="action_button question_button" id="QA_1">Avec qui étiez vous ?</button>
|
||||
</div>
|
||||
</section>
|
||||
<section class="results_game hidden">
|
||||
|
@ -17,15 +17,6 @@
|
||||
</head>
|
||||
<body class="game_app">
|
||||
<section class="game_start">
|
||||
<menu class="header_actions">
|
||||
<li class="header_action">
|
||||
<button class="theme_switcher" aria-label="Changer de thème">
|
||||
<svg class="theme_switcher_btn" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
|
||||
<path d="M24 34q-4.15 0-7.075-2.925T14 24q0-4.15 2.925-7.075T24 14q4.15 0 7.075 2.925T34 24q0 4.15-2.925 7.075T24 34ZM2 25.5v-3h8v3Zm36 0v-3h8v3ZM22.5 10V2h3v8Zm0 36v-8h3v8Zm-9.45-30.85L8.1 10.2l2.1-2.1 4.95 4.95ZM37.8 39.9l-4.95-4.95 2.1-2.1 4.95 4.95Zm-2.85-24.75-2.1-2.1L37.8 8.1l2.1 2.1ZM10.2 39.9l-2.1-2.1 4.95-4.95 2.1 2.1Z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
</menu>
|
||||
<div class="game_begin">
|
||||
<h1 class="game_title">Truth Inquiry</h1>
|
||||
<button class="action_button" id="play_button">Jouer</button>
|
||||
|
@ -16,6 +16,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body class="game_app">
|
||||
<div class="current_background"></div>
|
||||
<input type="hidden" id="game_id" name="game_id" value={{gameid}}>
|
||||
<section class="join_room_view hidden">
|
||||
<h1 class="room_title">Salon</h1>
|
||||
|