Merge pull request #38 from ThomasRubini/game_logic_front_end
Game logic front end
This commit is contained in:
commit
226df72eb2
@ -23,7 +23,7 @@ class TruthSeekerApp(flask.Flask):
|
|||||||
|
|
||||||
self.config["SECRET_KEY"] = os.getenv("FLASK_SECRET")
|
self.config["SECRET_KEY"] = os.getenv("FLASK_SECRET")
|
||||||
|
|
||||||
self.socketio_app = SocketIO(self)
|
self.socketio_app = SocketIO(self,cors_allowed_origins=["https://truthinquiry.simailadjalim.fr","http://127.0.0.1:5000"])
|
||||||
|
|
||||||
self.discord_bot = discord_bot.DiscordBot()
|
self.discord_bot = discord_bot.DiscordBot()
|
||||||
token = os.getenv("DISCORD_BOT_TOKEN")
|
token = os.getenv("DISCORD_BOT_TOKEN")
|
||||||
|
@ -47,6 +47,10 @@ def get_trait_from_trait_id(trait_id):
|
|||||||
trait = session.query(tables.Trait).filter_by(TRAIT_ID=trait_id).one()
|
trait = session.query(tables.Trait).filter_by(TRAIT_ID=trait_id).one()
|
||||||
return trait
|
return trait
|
||||||
|
|
||||||
|
def get_reaction_description(lang,npc_id,trait_id):
|
||||||
|
desc_lid = session.query(tables.Reaction).filter_by(NPC_ID=npc_id,TRAIT_ID=trait_id).one().DESC_LID
|
||||||
|
return get_text_from_lid(lang,desc_lid)
|
||||||
|
|
||||||
def get_traits(lang):
|
def get_traits(lang):
|
||||||
traits = []
|
traits = []
|
||||||
for trait in session.query(tables.Trait).all():
|
for trait in session.query(tables.Trait).all():
|
||||||
|
@ -78,6 +78,7 @@ class Game:
|
|||||||
traitId = self.reaction_table[npc_id]
|
traitId = self.reaction_table[npc_id]
|
||||||
trait = get_trait_from_trait_id(traitId)
|
trait = get_trait_from_trait_id(traitId)
|
||||||
npcs[npc_id]["reaction"] = get_text_from_lid("FR",trait.NAME_LID)
|
npcs[npc_id]["reaction"] = get_text_from_lid("FR",trait.NAME_LID)
|
||||||
|
npcs[npc_id]["description"] = get_reaction_description("FR",npc_id,trait.TRAIT_ID)
|
||||||
player_results = data["player"] = {}
|
player_results = data["player"] = {}
|
||||||
for member in self.members:
|
for member in self.members:
|
||||||
player_results[member.username] = member.results
|
player_results[member.username] = member.results
|
||||||
@ -89,6 +90,7 @@ class Game:
|
|||||||
"""
|
"""
|
||||||
#TODO Get language from player
|
#TODO Get language from player
|
||||||
self.gamedata, self.reaction_table = generate_game_data("FR")
|
self.gamedata, self.reaction_table = generate_game_data("FR")
|
||||||
|
self.gamedata["game_id"] = self.game_id
|
||||||
|
|
||||||
def get_member(self, username: str) -> Union[Member, None]:
|
def get_member(self, username: str) -> Union[Member, None]:
|
||||||
"""
|
"""
|
||||||
@ -114,13 +116,13 @@ class Game:
|
|||||||
self.members.append(member)
|
self.members.append(member)
|
||||||
return member
|
return member
|
||||||
|
|
||||||
def get_npc_reaction(self, npc_id, reaction) -> None:
|
def get_npc_reaction(self, npc_id) -> None:
|
||||||
"""
|
"""
|
||||||
TODO + TODO TYPES
|
TODO + TODO TYPES
|
||||||
"""
|
"""
|
||||||
if npc_id not in self.reaction_table.keys():
|
if npc_id not in self.reaction_table.keys():
|
||||||
return 0
|
return 0
|
||||||
reaction_id = self.reaction_table[npc_id][int(reaction)]
|
reaction_id = self.reaction_table[npc_id]
|
||||||
return read_image(f"./truthseeker/static/images/npc/{npc_id}/{reaction_id}.png")
|
return read_image(f"./truthseeker/static/images/npc/{npc_id}/{reaction_id}.png")
|
||||||
|
|
||||||
def get_player_results(self, responses: dict) -> None:
|
def get_player_results(self, responses: dict) -> None:
|
||||||
@ -131,7 +133,7 @@ class Game:
|
|||||||
try:
|
try:
|
||||||
for npc_id in responses:
|
for npc_id in responses:
|
||||||
trait_id = get_trait_id_from_string(responses[npc_id])
|
trait_id = get_trait_id_from_string(responses[npc_id])
|
||||||
results[npc_id] = trait_id == str(self.reaction_table[npc_id])
|
results[npc_id] = trait_id == self.reaction_table[npc_id]
|
||||||
return results
|
return results
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
@ -120,8 +120,11 @@ def get_data():
|
|||||||
@routes_api.route("/getNpcImage", methods=["GET", "POST"])
|
@routes_api.route("/getNpcImage", methods=["GET", "POST"])
|
||||||
def getNpcImage():
|
def getNpcImage():
|
||||||
npc_id = flask.request.values.get("npcid")
|
npc_id = flask.request.values.get("npcid")
|
||||||
|
if npc_id is None:
|
||||||
|
return {"error": 1, "msg": "no npc was given"}
|
||||||
image = game_logic.get_npc_image(npc_id)
|
image = game_logic.get_npc_image(npc_id)
|
||||||
|
if image is None:
|
||||||
|
return {"error": 1, "msg": "npc not found"}
|
||||||
response = flask.make_response(image)
|
response = flask.make_response(image)
|
||||||
response.headers.set('Content-Type', 'image/png')
|
response.headers.set('Content-Type', 'image/png')
|
||||||
response.headers.set(
|
response.headers.set(
|
||||||
@ -137,9 +140,8 @@ def getNpcReaction():
|
|||||||
if game == None:
|
if game == None:
|
||||||
return {"error": 1, "msg": "this game doesn't exist"}
|
return {"error": 1, "msg": "this game doesn't exist"}
|
||||||
npc_id = flask.request.values.get("npcid")
|
npc_id = flask.request.values.get("npcid")
|
||||||
reactionid = flask.request.values.get("reactionid")
|
|
||||||
image = game.get_npc_reaction(npc_id,reactionid)
|
|
||||||
|
|
||||||
|
image = game.get_npc_reaction(npc_id)
|
||||||
errors = ["npc not in game","error reading file"]
|
errors = ["npc not in game","error reading file"]
|
||||||
if image in [0,1]:
|
if image in [0,1]:
|
||||||
return {"error" :1, "msg": errors[image]} , 500
|
return {"error" :1, "msg": errors[image]} , 500
|
||||||
@ -147,7 +149,7 @@ def getNpcReaction():
|
|||||||
response = flask.make_response(image)
|
response = flask.make_response(image)
|
||||||
response.headers.set('Content-Type', 'image/png')
|
response.headers.set('Content-Type', 'image/png')
|
||||||
response.headers.set(
|
response.headers.set(
|
||||||
'Content-Disposition', 'attachment', filename=f'{reactionid}.png')
|
'Content-Disposition', 'attachment', filename=f'reaction.png')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@routes_api.route("/gameProgress", methods=["GET", "POST"])
|
@routes_api.route("/gameProgress", methods=["GET", "POST"])
|
||||||
@ -194,6 +196,7 @@ def checkAnwser():
|
|||||||
if game.has_finished():
|
if game.has_finished():
|
||||||
jsonGameResults = game.generate_game_results()
|
jsonGameResults = game.generate_game_results()
|
||||||
APP.socketio_app.emit("gamefinshed",jsonGameResults,room="game."+game.game_id)
|
APP.socketio_app.emit("gamefinshed",jsonGameResults,room="game."+game.game_id)
|
||||||
|
#TODO desctruct game
|
||||||
response = {"error": 0}
|
response = {"error": 0}
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -15,3 +15,14 @@ async function makeAPIRequest(endpoint, body){
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
async function makeAPIImageRequest(endpoint, body){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
const fetchOptions = {
|
||||||
|
method: "POST",
|
||||||
|
body: new URLSearchParams(body)
|
||||||
|
}
|
||||||
|
fetch("/api/v1/"+endpoint, fetchOptions).then(resp => {
|
||||||
|
resolve(resp)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
246
truthseeker/static/js/game.js
Normal file
246
truthseeker/static/js/game.js
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
var npcs_ids = []
|
||||||
|
var gamedata = {}
|
||||||
|
var currentNpc = null
|
||||||
|
var score = null
|
||||||
|
|
||||||
|
function show(className){
|
||||||
|
document.getElementsByClassName(className)[0].classList.remove("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide(className){
|
||||||
|
document.getElementsByClassName(className)[0].classList.add("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
function setListenerToIntroductionNextBtn(){
|
||||||
|
document.getElementById("introduction_next_btn").addEventListener("click", showInterogationViewFromIntroduction);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setListenerToInterrogationSuspectPreviousBtn(){
|
||||||
|
document.getElementById("interrogation_suspect_previous_btn").addEventListener("click",goBackToInterogation)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setListenerToInterrogationNextBtn(){
|
||||||
|
document.getElementById("interrogation_next_btn").addEventListener("click", showEmotionAndCulpritChoicesView)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setQuestionButtonsListeners(){
|
||||||
|
document.getElementById("QA_0").addEventListener("click",askTypeZeroQuestion);
|
||||||
|
document.getElementById("QA_1").addEventListener("click",askTypeOneQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
function goBackToInterogation(){
|
||||||
|
hide("interrogation_suspect");
|
||||||
|
show("interrogation");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showInterogationViewFromIntroduction(){
|
||||||
|
hide("introduction");
|
||||||
|
show("interrogation");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showEmotionAndCulpritChoicesView(){
|
||||||
|
hide("interrogation");
|
||||||
|
show("emotion_and_culprit_choices");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNpcLocationAndPartner(npcid){
|
||||||
|
data = {}
|
||||||
|
npcid = parseInt(npcid)
|
||||||
|
for(const room in gamedata["rooms"]){
|
||||||
|
if(gamedata["rooms"][room]["npcs"].includes(npcid)){
|
||||||
|
data["room"] = gamedata["rooms"][room]["name"];
|
||||||
|
if(gamedata["rooms"][room]["npcs"].length === 1){
|
||||||
|
do{
|
||||||
|
const random = Math.floor(Math.random() * npcs_ids.length);
|
||||||
|
data["partner"] = npcs_ids[random]
|
||||||
|
}while(data["partner"] === npcid);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
data["partner"] = gamedata["rooms"][room]["npcs"][gamedata["rooms"][room]["npcs"][1] === npcid ?0:1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getCulprit(){
|
||||||
|
culprit = null
|
||||||
|
Object.values(gamedata["rooms"]).forEach(element =>{
|
||||||
|
if (element['npcs'].length === 1){
|
||||||
|
culprit = element['npcs'][0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return culprit
|
||||||
|
}
|
||||||
|
|
||||||
|
async function askTypeOneQuestion(){
|
||||||
|
partnerId = getNpcLocationAndPartner(currentNpc)["partner"];
|
||||||
|
anwser = gamedata["npcs"][currentNpc]["QA_1"];
|
||||||
|
anwser = anwser.replace("{NPC}",gamedata["npcs"][partnerId]["name"]);
|
||||||
|
document.getElementsByClassName("suspect_answer")[0].textContent = anwser;
|
||||||
|
show("question_answer");
|
||||||
|
document.getElementById("currentNpcPicure").src = "/api/v1//getNpcReaction?npcid="+currentNpc;
|
||||||
|
//sleep for 5 sec
|
||||||
|
await new Promise(r => setTimeout(r, 5000));
|
||||||
|
document.getElementById("currentNpcPicure").src = "/api/v1/getNpcImage?npcid="+currentNpc;
|
||||||
|
hide("question_answer");
|
||||||
|
document.getElementsByClassName("suspect_answer")[0].textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function askTypeZeroQuestion(){
|
||||||
|
room = getNpcLocationAndPartner(currentNpc)["room"];
|
||||||
|
anwser = gamedata["npcs"][currentNpc]["QA_0"];
|
||||||
|
anwser = anwser.replace("{SALLE}",room);
|
||||||
|
document.getElementsByClassName("suspect_answer")[0].textContent = anwser;
|
||||||
|
show("question_answer");
|
||||||
|
document.getElementById("currentNpcPicure").src = "/api/v1//getNpcReaction?npcid="+currentNpc;
|
||||||
|
//sleep for 5 sec
|
||||||
|
await new Promise(r => setTimeout(r, 5000));
|
||||||
|
document.getElementById("currentNpcPicure").src = "/api/v1/getNpcImage?npcid="+currentNpc;
|
||||||
|
hide("question_answer");
|
||||||
|
document.getElementsByClassName("suspect_answer")[0].textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendAnswers(){
|
||||||
|
selects = document.getElementsByClassName("suspect_emotion_chooser");
|
||||||
|
let playerResponses = {}
|
||||||
|
for (let index = 0; index < selects.length; index++) {
|
||||||
|
select = selects[index];
|
||||||
|
playerResponses[select.id] = select.value
|
||||||
|
}
|
||||||
|
data = {};
|
||||||
|
data["responses"] = JSON.stringify(playerResponses);
|
||||||
|
return await makeAPIRequest("submitAnswers",data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderAnswerSelectionPanel() {
|
||||||
|
npcs_ids.forEach(element => {
|
||||||
|
let suspect = document.createElement("div");
|
||||||
|
suspect.classList.add("suspect");
|
||||||
|
|
||||||
|
suspect_emotion_chooser = document.createElement("select");
|
||||||
|
suspect_emotion_chooser.classList.add("suspect_emotion_chooser")
|
||||||
|
suspect_emotion_chooser.setAttribute("id",element);
|
||||||
|
gamedata["traits"].forEach(trait =>{
|
||||||
|
let option = document.createElement("option");
|
||||||
|
option.value = trait;
|
||||||
|
option.text = trait;
|
||||||
|
suspect_emotion_chooser.appendChild(option);
|
||||||
|
});
|
||||||
|
suspect.appendChild(suspect_emotion_chooser);
|
||||||
|
let data = {};
|
||||||
|
let img = document.createElement('img');
|
||||||
|
img.classList.add("suspect_picture");
|
||||||
|
img.src = "/api/v1/getNpcImage?npcid="+element;
|
||||||
|
suspect.appendChild(img);
|
||||||
|
let button = document.getElementById("culpritButton");
|
||||||
|
let button_clone = button.cloneNode(true);
|
||||||
|
button_clone.addEventListener("click",()=>{
|
||||||
|
sendAnswers();
|
||||||
|
});
|
||||||
|
button_clone.removeAttribute("id");
|
||||||
|
button_clone.classList.remove("hidden");
|
||||||
|
suspect.appendChild(button_clone);
|
||||||
|
document.getElementById("culprits_choices").appendChild(suspect);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderInterogation(){
|
||||||
|
document.getElementById("QA_0").textContent = gamedata["questions"]["QA_0"],
|
||||||
|
document.getElementById("QA_1").textContent = gamedata["questions"]["QA_1"],
|
||||||
|
npcs_ids.forEach(element => {
|
||||||
|
let suspect = document.createElement("div");
|
||||||
|
suspect.classList.add("suspect");
|
||||||
|
|
||||||
|
let img = document.createElement('img');
|
||||||
|
img.classList.add("suspect_picture");
|
||||||
|
img.src = "/api/v1/getNpcImage?npcid="+element;
|
||||||
|
suspect.appendChild(img);
|
||||||
|
let button = document.getElementById("interogationButton");
|
||||||
|
let button_clone = button.cloneNode(true);
|
||||||
|
button_clone.classList.remove("hidden");
|
||||||
|
button_clone.addEventListener("click",()=>{
|
||||||
|
currentNpc = element
|
||||||
|
document.getElementById("currentNpcPicure").src = "/api/v1/getNpcImage?npcid="+element;
|
||||||
|
hide("interrogation");
|
||||||
|
show("interrogation_suspect");
|
||||||
|
})
|
||||||
|
suspect.appendChild(button_clone)
|
||||||
|
document.getElementById("interrogation_suspects").appendChild(suspect);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSock(){
|
||||||
|
socket = io({
|
||||||
|
auth:{
|
||||||
|
game_id: gamedata["game_id"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("connect", () => {
|
||||||
|
console.log("Connected !")
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on("gameprogress", (username) => {
|
||||||
|
console.log(username);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("gamefinshed", (finalResults) => {
|
||||||
|
hide("emotion_and_culprit_choices");
|
||||||
|
console.log(finalResults);
|
||||||
|
for (const player in finalResults["player"]){
|
||||||
|
let playerNode = document.createElement("h3")
|
||||||
|
playerNode.classList.add("player_name_and_score")
|
||||||
|
let playerResultArray = Object.values(finalResults["player"][player])
|
||||||
|
playerNode.textContent = "" + player + " : " + playerResultArray.filter(x => x==true).length
|
||||||
|
document.getElementsByClassName("players_list")[0].appendChild(playerNode);
|
||||||
|
}
|
||||||
|
culprit = getCulprit();
|
||||||
|
document.getElementsByClassName("reveal_culprit_title")[0].textContent += " " + gamedata["npcs"][culprit]["name"];
|
||||||
|
document.getElementById("culprit").src = "/api/v1/getNpcImage?npcid="+culprit;
|
||||||
|
show("results_game");
|
||||||
|
npcs_ids.filter(x => x!=culprit).forEach(npcid =>{
|
||||||
|
let suspect = document.createElement("div");
|
||||||
|
suspect.classList.add("summary_suspect");
|
||||||
|
let img = document.createElement("img")
|
||||||
|
img.src = "/api/v1/getNpcImage?npcid=" + npcid;
|
||||||
|
suspect.appendChild(img)
|
||||||
|
|
||||||
|
let emotionTitle = document.createElement("h2");
|
||||||
|
emotionTitle.classList.add("explain_suspect_emotion_title");
|
||||||
|
emotionTitle.textContent = "Ce suspect était " + finalResults["npcs"][npcid]["reaction"];
|
||||||
|
suspect.appendChild(emotionTitle);
|
||||||
|
|
||||||
|
let emotionDesc = document.createElement("p");
|
||||||
|
emotionDesc.classList.add("explain_suspect_emotion_description");
|
||||||
|
emotionDesc.textContent = "Qui se caractérise par un " + finalResults["npcs"][npcid]["description"];
|
||||||
|
suspect.appendChild(emotionDesc)
|
||||||
|
|
||||||
|
document.getElementsByClassName("suspects_list")[0].appendChild(suspect)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setGameData(){
|
||||||
|
data = {};
|
||||||
|
response = await makeAPIRequest("getGameData");
|
||||||
|
gamedata = response["gamedata"];
|
||||||
|
npcs_ids = Object.keys(gamedata["npcs"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initGame(){
|
||||||
|
await setGameData();
|
||||||
|
initSock();
|
||||||
|
renderAnswerSelectionPanel();
|
||||||
|
renderInterogation();
|
||||||
|
setQuestionButtonsListeners()
|
||||||
|
setListenerToInterrogationSuspectPreviousBtn()
|
||||||
|
setListenerToIntroductionNextBtn()
|
||||||
|
setListenerToInterrogationNextBtn();
|
||||||
|
show("introduction");
|
||||||
|
}
|
||||||
|
initGame();
|
@ -108,16 +108,6 @@ function areInputsValid(checkRoomCode) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startSoloGame() {
|
|
||||||
if (!areInputsValid(false)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hideInvalidInputErrorMessage();
|
|
||||||
|
|
||||||
//TODO: code to start solo game
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMultiPlayerRoom() {
|
function createMultiPlayerRoom() {
|
||||||
if (!areInputsValid(false)) {
|
if (!areInputsValid(false)) {
|
||||||
return;
|
return;
|
||||||
@ -209,6 +199,13 @@ function changeTheme() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function startSoloGame(){
|
async function startSoloGame(){
|
||||||
|
|
||||||
|
if (!areInputsValid(false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideInvalidInputErrorMessage();
|
||||||
|
|
||||||
username = document.getElementById("game_username").value;
|
username = document.getElementById("game_username").value;
|
||||||
let data = {}
|
let data = {}
|
||||||
data["username"] = username;
|
data["username"] = username;
|
||||||
|
@ -26,12 +26,7 @@
|
|||||||
<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">
|
<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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="suspects">
|
<div class="suspects" id="interrogation_suspects">
|
||||||
<!-- TODO: model, remove from HTML and add it dynamically with JavaScript for each suspect -->
|
|
||||||
<div class="suspect">
|
|
||||||
<img class="suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
|
||||||
<button class="ask_button action_button">Interroger</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="emotion_and_culprit_choices hidden">
|
<div class="emotion_and_culprit_choices hidden">
|
||||||
@ -41,27 +36,7 @@
|
|||||||
<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">
|
<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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="suspects">
|
<div class="suspects" id="culprits_choices">
|
||||||
<!-- TODO: model, remove from HTML and add it dynamically with JavaScript for each suspect -->
|
|
||||||
<div class="suspect">
|
|
||||||
<select class="suspect_emotion_chooser" required="required">
|
|
||||||
<!-- This is the place holder value-->
|
|
||||||
<option value="">Choisissez une émotion</option>
|
|
||||||
<!-- Add other emotions here -->
|
|
||||||
</select>
|
|
||||||
<img class="suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
|
||||||
<!-- Add culprit_btn_checked class when a choice is checked -->
|
|
||||||
<!-- Only one button can be checked at a time, so when one is checked, the previous one, if applicable, is unchecked -->
|
|
||||||
<button class="culprit_btn action_button">
|
|
||||||
<svg class="culprit_checked_icon hidden culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48">
|
|
||||||
<path d="M18.9 36.75 6.65 24.5l3.3-3.3 8.95 9L38 11.1l3.3 3.25Z"></path>
|
|
||||||
</svg>
|
|
||||||
<svg class="culprit_unchecked_icon culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48">
|
|
||||||
<path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z">
|
|
||||||
</svg>
|
|
||||||
<p class="culprit_btn_text">Couplable</p>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="interrogation_suspect hidden">
|
<div class="interrogation_suspect hidden">
|
||||||
@ -72,10 +47,10 @@
|
|||||||
<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"/>
|
<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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<img class="image_interrogation suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
<img class="image_interrogation suspect_picture" id="currentNpcPicure" src="">
|
||||||
<div class="questions_list">
|
<div class="questions_list">
|
||||||
<button class="action_button question_button">Où étiez vous hier soir ?</button>
|
<button class="action_button question_button" id="QA_0" >Où étiez vous hier soir ?</button>
|
||||||
<button class="action_button question_button">Avec qui étiez vous ?</button>
|
<button class="action_button question_button" id="QA_1" >Avec qui étiez vous ?</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="question_answer hidden">
|
<div class="question_answer hidden">
|
||||||
<h1 class="anwser_title">Réponse du suspect à la question</h1>
|
<h1 class="anwser_title">Réponse du suspect à la question</h1>
|
||||||
@ -93,42 +68,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="results_game_multiplayer">
|
<div class="results_game_multiplayer">
|
||||||
<div class="players_list">
|
<div class="players_list">
|
||||||
<!-- TODO: model, remove from HTML and add it dynamically with JavaScript for each player -->
|
|
||||||
<h3 class="player_name_and_score">nom : score</h3>
|
|
||||||
<h3 class="player_name_and_score">nom : score</h3>
|
|
||||||
<h3 class="player_name_and_score">nom : score</h3>
|
|
||||||
<h3 class="player_name_and_score">nom : score</h3>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="reveal_culprit">
|
<div class="reveal_culprit">
|
||||||
<h2 class="reveal_culprit_title">Le coupable était ...</h2>
|
<h2 class="reveal_culprit_title">Le coupable était ...</h2>
|
||||||
<img class="suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
<img class="suspect_picture" id="culprit" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
||||||
<h3 class="reveal_culprit_explaination">Ce suspect était le coupable car il ...</h3>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="summary">
|
<div class="summary">
|
||||||
<h1 class="summary_title">Débrief</h1>
|
<h1 class="summary_title">Débrief</h1>
|
||||||
<div class="suspects_list">
|
<div class="suspects_list">
|
||||||
<div class="summary_suspect">
|
|
||||||
<img class="suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
|
||||||
<h2 class="explain_suspect_emotion_title">Ce suspect était ...</h2>
|
|
||||||
<p class="explain_suspect_emotion_description">En effet, la ... se caractérise par un ...</p>
|
|
||||||
</div>
|
|
||||||
<div class="summary_suspect">
|
|
||||||
<img class="suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
|
||||||
<h2 class="explain_suspect_emotion_title">Ce suspect était ...</h2>
|
|
||||||
<p class="explain_suspect_emotion_description">En effet, la ... se caractérise par un ...</p>
|
|
||||||
</div>
|
|
||||||
<div class="summary_suspect">
|
|
||||||
<img class="suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
|
||||||
<h2 class="explain_suspect_emotion_title">Ce suspect était ...</h2>
|
|
||||||
<p class="explain_suspect_emotion_description">En effet, la ... se caractérise par un ...</p>
|
|
||||||
</div>
|
|
||||||
<div class="summary_suspect">
|
|
||||||
<img class="suspect_picture" src="/static/images/suspect_example.png" alt="Example" draggable="false">
|
|
||||||
<h2 class="explain_suspect_emotion_title">Ce suspect était ...</h2>
|
|
||||||
<p class="explain_suspect_emotion_description">En effet, la ... se caractérise par un ...</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -148,6 +98,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
<!-- buttons to clone in js-->
|
||||||
|
<button class="ask_button action_button hidden" id="interogationButton">Interroger</button>
|
||||||
|
<!-- Add culprit_btn_checked class when a choice is checked -->
|
||||||
|
<!-- Only one button can be checked at a time, so when one is checked, the previous one, if applicable, is unchecked -->
|
||||||
|
<button class="culprit_btn action_button hidden", id="culpritButton">
|
||||||
|
<svg class="culprit_checked_icon hidden culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48">
|
||||||
|
<path d="M18.9 36.75 6.65 24.5l3.3-3.3 8.95 9L38 11.1l3.3 3.25Z"></path>
|
||||||
|
</svg>
|
||||||
|
<svg class="culprit_unchecked_icon culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48">
|
||||||
|
<path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z">
|
||||||
|
</svg>
|
||||||
|
<p class="culprit_btn_text">Couplable</p>
|
||||||
|
</button>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.min.js"></script>
|
||||||
|
<script src="/static/js/api.js"></script>
|
||||||
<script src="/static/js/game_common.js"></script>
|
<script src="/static/js/game_common.js"></script>
|
||||||
|
<script src="/static/js/game.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user