2019-09-14 12:59:34 +02:00
|
|
|
|
// swad_match.c: matches in games using remote control
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
SWAD (Shared Workspace At a Distance),
|
|
|
|
|
is a web platform developed at the University of Granada (Spain),
|
|
|
|
|
and used to support university teaching.
|
|
|
|
|
|
|
|
|
|
This file is part of SWAD core.
|
2020-01-01 14:53:57 +01:00
|
|
|
|
Copyright (C) 1999-2020 Antonio Ca<EFBFBD>as Vargas
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU Affero General Public License as
|
|
|
|
|
published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************************* Headers ***********************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#define _GNU_SOURCE // For asprintf
|
|
|
|
|
#include <linux/limits.h> // For PATH_MAX
|
2019-12-29 12:39:00 +01:00
|
|
|
|
#include <stddef.h> // For NULL
|
2019-09-14 12:59:34 +02:00
|
|
|
|
#include <stdio.h> // For asprintf
|
|
|
|
|
#include <stdlib.h> // For calloc
|
|
|
|
|
#include <string.h> // For string functions
|
|
|
|
|
|
|
|
|
|
#include "swad_database.h"
|
2019-09-30 01:23:24 +02:00
|
|
|
|
#include "swad_date.h"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
#include "swad_form.h"
|
|
|
|
|
#include "swad_game.h"
|
|
|
|
|
#include "swad_global.h"
|
2019-10-23 19:05:05 +02:00
|
|
|
|
#include "swad_HTML.h"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
#include "swad_match.h"
|
2019-09-28 02:31:42 +02:00
|
|
|
|
#include "swad_match_result.h"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
#include "swad_role.h"
|
|
|
|
|
#include "swad_setting.h"
|
|
|
|
|
#include "swad_test.h"
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************** External global variables from others modules ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
extern struct Globals Gbl;
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************************** Private constants *****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#define Mch_ICON_CLOSE "fas fa-times"
|
|
|
|
|
#define Mch_ICON_PLAY "fas fa-play"
|
|
|
|
|
#define Mch_ICON_PAUSE "fas fa-pause"
|
|
|
|
|
#define Mch_ICON_PREVIOUS "fas fa-step-backward"
|
|
|
|
|
#define Mch_ICON_NEXT "fas fa-step-forward"
|
|
|
|
|
#define Mch_ICON_RESULTS "fas fa-chart-bar"
|
|
|
|
|
|
2019-12-13 01:04:09 +01:00
|
|
|
|
#define Mch_COUNTDOWN_SECONDS_LARGE 60
|
|
|
|
|
#define Mch_COUNTDOWN_SECONDS_MEDIUM 30
|
|
|
|
|
#define Mch_COUNTDOWN_SECONDS_SMALL 10
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************************* Private types *******************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-03 02:46:46 +01:00
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
Mch_CHANGE_STATUS_BY_STUDENT,
|
|
|
|
|
Mch_REFRESH_STATUS_BY_SERVER,
|
|
|
|
|
} Mch_Update_t;
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************************** Private constants *****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
const char *Mch_ShowingStringsDB[Mch_NUM_SHOWING] =
|
|
|
|
|
{
|
2019-12-10 21:52:22 +01:00
|
|
|
|
[Mch_START ] = "start",
|
|
|
|
|
[Mch_STEM ] = "stem",
|
|
|
|
|
[Mch_ANSWERS] = "answers",
|
|
|
|
|
[Mch_RESULTS] = "results",
|
|
|
|
|
[Mch_END ] = "end",
|
2019-09-14 12:59:34 +02:00
|
|
|
|
};
|
|
|
|
|
|
2019-10-23 02:18:24 +02:00
|
|
|
|
#define Mch_MAX_COLS 4
|
2019-10-22 22:39:37 +02:00
|
|
|
|
#define Mch_NUM_COLS_DEFAULT 1
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************************** Private variables *****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
long Mch_CurrentMchCod = -1L; // Used as parameter in contextual links
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************************** Private prototypes ****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-07 02:12:13 +01:00
|
|
|
|
static void Mch_PutIconsInListOfMatches (void);
|
2019-09-30 10:51:44 +02:00
|
|
|
|
static void Mch_PutIconToCreateNewMatch (void);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ListOneOrMoreMatches (const struct Game *Game,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
unsigned NumMatches,
|
|
|
|
|
MYSQL_RES *mysql_res);
|
2019-09-29 19:36:32 +02:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesHeading (bool ICanEditMatches);
|
2019-09-29 18:44:40 +02:00
|
|
|
|
static bool Mch_CheckIfICanEditMatches (void);
|
2019-09-30 01:10:57 +02:00
|
|
|
|
static bool Mch_CheckIfICanEditThisMatch (const struct Match *Match);
|
2019-09-25 09:29:44 +02:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesIcons (const struct Match *Match);
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesAuthor (const struct Match *Match);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesTimes (const struct Match *Match,unsigned UniqueId);
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesTitleGrps (const struct Match *Match);
|
|
|
|
|
static void Mch_GetAndWriteNamesOfGrpsAssociatedToMatch (const struct Match *Match);
|
2019-09-25 09:29:44 +02:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesNumPlayers (const struct Match *Match);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesStatus (const struct Match *Match,unsigned NumQsts);
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesResult (const struct Match *Match);
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesResultStd (const struct Match *Match);
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesResultTch (const struct Match *Match);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_GetMatchDataFromRow (MYSQL_RES *mysql_res,
|
|
|
|
|
struct Match *Match);
|
|
|
|
|
static Mch_Showing_t Mch_GetShowingFromStr (const char *Str);
|
|
|
|
|
|
2019-09-27 20:00:47 +02:00
|
|
|
|
static void Mch_RemoveMatchFromAllTables (long MchCod);
|
|
|
|
|
static void Mch_RemoveMatchFromTable (long MchCod,const char *TableName);
|
2019-09-28 01:12:53 +02:00
|
|
|
|
static void Mch_RemoveMatchesInGameFromTable (long GamCod,const char *TableName);
|
|
|
|
|
static void Mch_RemoveMatchInCourseFromTable (long CrsCod,const char *TableName);
|
2019-09-29 23:13:20 +02:00
|
|
|
|
static void Mch_RemoveUsrMchResultsInCrs (long UsrCod,long CrsCod,const char *TableName);
|
2019-09-27 20:00:47 +02:00
|
|
|
|
|
2019-09-29 22:38:32 +02:00
|
|
|
|
static void Mch_PutParamsPlay (void);
|
2019-09-30 01:10:57 +02:00
|
|
|
|
static void Mch_PutParamMchCod (long MchCod);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_PutFormNewMatch (const struct Game *Game);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_ShowLstGrpsToCreateMatch (void);
|
|
|
|
|
|
|
|
|
|
static long Mch_CreateMatch (long GamCod,char Title[Gam_MAX_BYTES_TITLE + 1]);
|
2019-09-23 21:39:54 +02:00
|
|
|
|
static void Mch_CreateIndexes (long GamCod,long MchCod);
|
|
|
|
|
static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
|
|
|
|
|
long QstCod,bool Shuffle);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_CreateGrps (long MchCod);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_UpdateMatchStatusInDB (const struct Match *Match);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_UpdateElapsedTimeInQuestion (const struct Match *Match);
|
|
|
|
|
static void Mch_GetElapsedTimeInQuestion (const struct Match *Match,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
struct Time *Time);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_GetElapsedTimeInMatch (const struct Match *Match,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
struct Time *Time);
|
|
|
|
|
static void Mch_GetElapsedTime (unsigned NumRows,MYSQL_RES *mysql_res,
|
|
|
|
|
struct Time *Time);
|
|
|
|
|
|
|
|
|
|
static void Mch_SetMatchStatusToPrev (struct Match *Match);
|
2019-09-17 15:42:41 +02:00
|
|
|
|
static void Mch_SetMatchStatusToPrevQst (struct Match *Match);
|
|
|
|
|
static void Mch_SetMatchStatusToStart (struct Match *Match);
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_SetMatchStatusToNext (struct Match *Match);
|
2019-09-17 15:42:41 +02:00
|
|
|
|
static void Mch_SetMatchStatusToNextQst (struct Match *Match);
|
|
|
|
|
static void Mch_SetMatchStatusToEnd (struct Match *Match);
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_ShowMatchStatusForTch (struct Match *Match);
|
2019-12-03 02:46:46 +01:00
|
|
|
|
static void Mch_ShowMatchStatusForStd (struct Match *Match,Mch_Update_t Update);
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_ShowLeftColumnTch (struct Match *Match);
|
2019-09-30 16:25:44 +02:00
|
|
|
|
static void Mch_ShowRefreshablePartTch (struct Match *Match);
|
2019-12-12 09:14:26 +01:00
|
|
|
|
static void Mch_WriteElapsedTimeInMch (struct Match *Match);
|
|
|
|
|
static void Mch_WriteElapsedTimeInQst (struct Match *Match);
|
|
|
|
|
static void Mch_WriteNumRespondersQst (struct Match *Match);
|
2019-12-14 01:31:32 +01:00
|
|
|
|
static void Mch_PutFormCountdown (struct Match *Match,long Seconds,const char *Color);
|
|
|
|
|
static void Mch_PutCountdownAndHourglassIcon (struct Match *Match);
|
|
|
|
|
static void Mch_PutFormsCountdown (struct Match *Match);
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowRightColumnTch (const struct Match *Match);
|
|
|
|
|
static void Mch_ShowLeftColumnStd (const struct Match *Match,
|
2019-12-03 02:46:46 +01:00
|
|
|
|
const struct Mch_UsrAnswer *UsrAnswer);
|
|
|
|
|
static void Mch_ShowRightColumnStd (struct Match *Match,
|
|
|
|
|
const struct Mch_UsrAnswer *UsrAnswer,
|
|
|
|
|
Mch_Update_t Update);
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
static void Mch_ShowNumQstInMch (const struct Match *Match);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_PutMatchControlButtons (const struct Match *Match);
|
|
|
|
|
static void Mch_ShowFormColumns (const struct Match *Match);
|
2019-10-23 00:49:03 +02:00
|
|
|
|
static void Mch_PutParamNumCols (unsigned NumCols);
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowMatchTitle (const struct Match *Match);
|
|
|
|
|
static void Mch_PutCheckboxResult (const struct Match *Match);
|
2019-12-03 02:46:46 +01:00
|
|
|
|
static void Mch_PutIfAnswered (const struct Match *Match,bool Answered);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_PutIconToRemoveMyAnswer (const struct Match *Match);
|
|
|
|
|
static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match);
|
|
|
|
|
static void Mch_WriteAnswersMatchResult (const struct Match *Match,
|
2019-10-23 01:30:11 +02:00
|
|
|
|
const char *Class,bool ShowResult);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static bool Mch_ShowQuestionAndAnswersStd (const struct Match *Match,
|
2019-12-03 02:46:46 +01:00
|
|
|
|
const struct Mch_UsrAnswer *UsrAnswer,
|
|
|
|
|
Mch_Update_t Update);
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowMatchScore (const struct Match *Match);
|
2019-12-14 01:31:32 +01:00
|
|
|
|
static void Mch_DrawEmptyScoreRow (unsigned NumRow,double MinScore,double MaxScore);
|
2019-10-21 15:07:00 +02:00
|
|
|
|
static void Mch_DrawScoreRow (double Score,double MinScore,double MaxScore,
|
2019-10-21 21:36:31 +02:00
|
|
|
|
unsigned NumRow,unsigned NumUsrs,unsigned MaxUsrs);
|
|
|
|
|
static const char *Mch_GetClassBorder (unsigned NumRow);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-24 01:41:51 +02:00
|
|
|
|
static void Mch_PutParamNumOpt (unsigned NumOpt);
|
|
|
|
|
static unsigned Mch_GetParamNumOpt (void);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-17 22:47:44 +02:00
|
|
|
|
static void Mch_PutBigButton (Act_Action_t NextAction,const char *Id,
|
|
|
|
|
long MchCod,const char *Icon,const char *Txt);
|
2019-12-13 00:36:01 +01:00
|
|
|
|
static void Mch_PutBigButtonHidden (const char *Icon);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_PutBigButtonClose (void);
|
|
|
|
|
|
|
|
|
|
static void Mch_ShowWaitImage (const char *Txt);
|
|
|
|
|
|
|
|
|
|
static void Mch_RemoveOldPlayers (void);
|
|
|
|
|
static void Mch_UpdateMatchAsBeingPlayed (long MchCod);
|
|
|
|
|
static void Mch_SetMatchAsNotBeingPlayed (long MchCod);
|
|
|
|
|
static bool Mch_GetIfMatchIsBeingPlayed (long MchCod);
|
|
|
|
|
static void Mch_GetNumPlayers (struct Match *Match);
|
|
|
|
|
|
2019-12-10 21:52:22 +01:00
|
|
|
|
static void Mch_RemoveMyAnswerToMatchQuestion (const struct Match *Match);
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
2019-09-24 21:29:01 +02:00
|
|
|
|
static double Mch_ComputeScore (unsigned NumQsts);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-16 00:15:40 +02:00
|
|
|
|
static unsigned Mch_GetNumUsrsWhoHaveChosenAns (long MchCod,unsigned QstInd,unsigned AnsInd);
|
2019-09-17 20:44:29 +02:00
|
|
|
|
static unsigned Mch_GetNumUsrsWhoHaveAnswerMch (long MchCod);
|
2019-12-12 09:14:26 +01:00
|
|
|
|
static void Mch_DrawBarNumUsrs (unsigned NumRespondersAns,unsigned NumRespondersQst,bool Correct);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-08 23:19:16 +01:00
|
|
|
|
static long Mch_GetCurrentMchCod (void);
|
2019-09-29 22:38:32 +02:00
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************************* List the matches of a game ************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_ListMatches (struct Game *Game,bool PutFormNewMatch)
|
|
|
|
|
{
|
|
|
|
|
extern const char *Hlp_ASSESSMENT_Games_matches;
|
|
|
|
|
extern const char *Txt_Matches;
|
|
|
|
|
char *SubQuery;
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
unsigned NumMatches;
|
|
|
|
|
|
|
|
|
|
/***** Get data of matches from database *****/
|
|
|
|
|
/* Fill subquery for game */
|
2019-09-29 17:33:39 +02:00
|
|
|
|
if (Gbl.Crs.Grps.WhichGrps == Grp_MY_GROUPS)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
if (asprintf (&SubQuery," AND"
|
|
|
|
|
"(MchCod NOT IN"
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" (SELECT MchCod FROM mch_groups)"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" OR"
|
|
|
|
|
" MchCod IN"
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" (SELECT mch_groups.MchCod"
|
|
|
|
|
" FROM mch_groups,crs_grp_usr"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE crs_grp_usr.UsrCod=%ld"
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" AND mch_groups.GrpCod=crs_grp_usr.GrpCod))",
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Gbl.Usrs.Me.UsrDat.UsrCod) < 0)
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
|
}
|
|
|
|
|
else // Gbl.Crs.Grps.WhichGrps == Grp_ALL_GROUPS
|
|
|
|
|
if (asprintf (&SubQuery,"%s","") < 0)
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
|
|
|
|
|
|
/* Make query */
|
|
|
|
|
NumMatches = (unsigned) DB_QuerySELECT (&mysql_res,"can not get matches",
|
2019-09-25 21:58:12 +02:00
|
|
|
|
"SELECT MchCod," // row[ 0]
|
|
|
|
|
"GamCod," // row[ 1]
|
|
|
|
|
"UsrCod," // row[ 2]
|
|
|
|
|
"UNIX_TIMESTAMP(StartTime)," // row[ 3]
|
|
|
|
|
"UNIX_TIMESTAMP(EndTime)," // row[ 4]
|
|
|
|
|
"Title," // row[ 5]
|
|
|
|
|
"QstInd," // row[ 6]
|
|
|
|
|
"QstCod," // row[ 7]
|
|
|
|
|
"Showing," // row[ 8]
|
2019-12-12 18:24:23 +01:00
|
|
|
|
"Countdown," // row[ 9]
|
|
|
|
|
"NumCols," // row[10]
|
|
|
|
|
"ShowQstResults," // row[11]
|
|
|
|
|
"ShowUsrResults" // row[12]
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" FROM mch_matches"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE GamCod=%ld%s"
|
|
|
|
|
" ORDER BY MchCod",
|
|
|
|
|
Game->GamCod,
|
|
|
|
|
SubQuery);
|
|
|
|
|
|
|
|
|
|
/* Free allocated memory for subquery */
|
2019-11-06 19:45:20 +01:00
|
|
|
|
free (SubQuery);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-26 02:19:42 +02:00
|
|
|
|
/***** Begin box *****/
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_SetCurrentGamCod (Game->GamCod); // Used to pass parameter
|
2019-12-08 17:08:15 +01:00
|
|
|
|
Box_BoxBegin ("100%",Txt_Matches,Mch_PutIconsInListOfMatches,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Hlp_ASSESSMENT_Games_matches,Box_NOT_CLOSABLE);
|
|
|
|
|
|
2019-09-29 17:33:39 +02:00
|
|
|
|
/***** Select whether show only my groups or all groups *****/
|
|
|
|
|
if (Gbl.Crs.Grps.NumGrps)
|
|
|
|
|
{
|
|
|
|
|
Set_StartSettingsHead ();
|
|
|
|
|
Grp_ShowFormToSelWhichGrps (ActSeeGam,Gam_PutParams);
|
|
|
|
|
Set_EndSettingsHead ();
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
if (NumMatches)
|
|
|
|
|
/***** Show the table with the matches *****/
|
|
|
|
|
Mch_ListOneOrMoreMatches (Game,NumMatches,mysql_res);
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
|
|
|
|
|
/***** Put button to play a new match in this game *****/
|
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_NET:
|
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_SYS_ADM:
|
|
|
|
|
if (PutFormNewMatch)
|
|
|
|
|
Mch_PutFormNewMatch (Game); // Form to fill in data and start playing a new match
|
|
|
|
|
else
|
2019-09-29 17:33:39 +02:00
|
|
|
|
Gam_PutButtonNewMatch (Game->GamCod); // Button to create a new match
|
2019-09-14 12:59:34 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** End box *****/
|
2019-10-25 22:48:34 +02:00
|
|
|
|
Box_BoxEnd ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Get match data using its code ************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-28 02:31:42 +02:00
|
|
|
|
void Mch_GetDataOfMatchByCod (struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
unsigned long NumRows;
|
2019-09-22 19:50:24 +02:00
|
|
|
|
Dat_StartEndTime_t StartEndTime;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Get data of match from database *****/
|
|
|
|
|
NumRows = (unsigned) DB_QuerySELECT (&mysql_res,"can not get matches",
|
2019-09-25 21:58:12 +02:00
|
|
|
|
"SELECT MchCod," // row[ 0]
|
|
|
|
|
"GamCod," // row[ 1]
|
|
|
|
|
"UsrCod," // row[ 2]
|
|
|
|
|
"UNIX_TIMESTAMP(StartTime)," // row[ 3]
|
|
|
|
|
"UNIX_TIMESTAMP(EndTime)," // row[ 4]
|
|
|
|
|
"Title," // row[ 5]
|
|
|
|
|
"QstInd," // row[ 6]
|
|
|
|
|
"QstCod," // row[ 7]
|
|
|
|
|
"Showing," // row[ 8]
|
2019-12-12 18:24:23 +01:00
|
|
|
|
"Countdown," // row[ 9]
|
|
|
|
|
"NumCols," // row[10]
|
|
|
|
|
"ShowQstResults," // row[11]
|
|
|
|
|
"ShowUsrResults" // row[12]
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" FROM mch_matches"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE MchCod=%ld"
|
|
|
|
|
" AND GamCod IN" // Extra check
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" (SELECT GamCod FROM gam_games"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE CrsCod='%ld')",
|
|
|
|
|
Match->MchCod,
|
|
|
|
|
Gbl.Hierarchy.Crs.CrsCod);
|
|
|
|
|
if (NumRows) // Match found...
|
|
|
|
|
/***** Get match data from row *****/
|
|
|
|
|
Mch_GetMatchDataFromRow (mysql_res,Match);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Initialize to empty match */
|
|
|
|
|
Match->MchCod = -1L;
|
|
|
|
|
Match->GamCod = -1L;
|
|
|
|
|
Match->UsrCod = -1L;
|
2019-12-15 20:02:34 +01:00
|
|
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
2019-09-22 19:50:24 +02:00
|
|
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
|
|
|
StartEndTime++)
|
|
|
|
|
Match->TimeUTC[StartEndTime] = (time_t) 0;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Match->Title[0] = '\0';
|
|
|
|
|
Match->Status.QstInd = 0;
|
|
|
|
|
Match->Status.QstCod = -1L;
|
|
|
|
|
Match->Status.QstStartTimeUTC = (time_t) 0;
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Match->Status.Showing = Mch_START;
|
2019-12-12 18:24:23 +01:00
|
|
|
|
Match->Status.Countdown = -1L;
|
2019-09-17 15:42:41 +02:00
|
|
|
|
Match->Status.Playing = false;
|
2019-09-25 21:58:12 +02:00
|
|
|
|
Match->Status.NumPlayers = 0;
|
2019-10-22 22:39:37 +02:00
|
|
|
|
Match->Status.NumCols = Mch_NUM_COLS_DEFAULT;
|
2019-09-25 21:58:12 +02:00
|
|
|
|
Match->Status.ShowQstResults = false;
|
|
|
|
|
Match->Status.ShowUsrResults = false;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-07 02:12:13 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Put icons in list of matches of a game *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_PutIconsInListOfMatches (void)
|
|
|
|
|
{
|
|
|
|
|
bool ICanEditMatches = Mch_CheckIfICanEditMatches ();
|
|
|
|
|
|
|
|
|
|
/***** Put icon to create a new match in current game *****/
|
|
|
|
|
if (ICanEditMatches)
|
|
|
|
|
Mch_PutIconToCreateNewMatch ();
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-29 17:33:39 +02:00
|
|
|
|
/********************* Put icon to create a new match ************************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-30 10:51:44 +02:00
|
|
|
|
static void Mch_PutIconToCreateNewMatch (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_New_match;
|
|
|
|
|
|
2019-09-29 17:33:39 +02:00
|
|
|
|
/***** Put form to create a new match *****/
|
2019-09-29 21:33:27 +02:00
|
|
|
|
Ico_PutContextualIconToAdd (ActReqNewMch,Mch_NEW_MATCH_SECTION_ID,Gam_PutParams,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Txt_New_match);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************** List game matches for edition ***********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ListOneOrMoreMatches (const struct Game *Game,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
unsigned NumMatches,
|
|
|
|
|
MYSQL_RES *mysql_res)
|
2019-09-25 00:42:13 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumMatch;
|
|
|
|
|
unsigned UniqueId;
|
|
|
|
|
struct Match Match;
|
2019-09-29 19:36:32 +02:00
|
|
|
|
bool ICanEditMatches = Mch_CheckIfICanEditMatches ();
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
|
|
|
|
/***** Write the heading *****/
|
2019-12-08 16:46:25 +01:00
|
|
|
|
HTM_TABLE_BeginWidePadding (2);
|
2019-09-29 19:36:32 +02:00
|
|
|
|
Mch_ListOneOrMoreMatchesHeading (ICanEditMatches);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
|
|
|
|
/***** Write rows *****/
|
|
|
|
|
for (NumMatch = 0, UniqueId = 1;
|
|
|
|
|
NumMatch < NumMatches;
|
|
|
|
|
NumMatch++, UniqueId++)
|
|
|
|
|
{
|
|
|
|
|
Gbl.RowEvenOdd = NumMatch % 2;
|
|
|
|
|
|
|
|
|
|
/***** Get match data from row *****/
|
|
|
|
|
Mch_GetMatchDataFromRow (mysql_res,&Match);
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
if (Mch_CheckIfICanPlayThisMatchBasedOnGrps (&Match))
|
|
|
|
|
{
|
|
|
|
|
/***** Write row for this match ****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Icons */
|
|
|
|
|
if (ICanEditMatches)
|
|
|
|
|
Mch_ListOneOrMoreMatchesIcons (&Match);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Match player */
|
|
|
|
|
Mch_ListOneOrMoreMatchesAuthor (&Match);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Start/end date/time */
|
|
|
|
|
Mch_ListOneOrMoreMatchesTimes (&Match,UniqueId);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Title and groups */
|
|
|
|
|
Mch_ListOneOrMoreMatchesTitleGrps (&Match);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Number of players who have answered any question in the match */
|
|
|
|
|
Mch_ListOneOrMoreMatchesNumPlayers (&Match);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Match status */
|
|
|
|
|
Mch_ListOneOrMoreMatchesStatus (&Match,Game->NumQsts);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Match result visible? */
|
|
|
|
|
Mch_ListOneOrMoreMatchesResult (&Match);
|
|
|
|
|
}
|
2019-09-25 00:42:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** End table *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TABLE_End ();
|
2019-09-25 00:42:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Put a column for match start and end times ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 19:36:32 +02:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesHeading (bool ICanEditMatches)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
|
|
|
|
|
extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME];
|
|
|
|
|
extern const char *Txt_Match;
|
2019-09-17 20:44:29 +02:00
|
|
|
|
extern const char *Txt_Players;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
extern const char *Txt_Status;
|
2019-09-25 00:18:23 +02:00
|
|
|
|
extern const char *Txt_Result;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-29 18:44:40 +02:00
|
|
|
|
/***** Start row *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-09-29 18:44:40 +02:00
|
|
|
|
|
|
|
|
|
/***** Column for icons *****/
|
2019-09-29 19:36:32 +02:00
|
|
|
|
if (ICanEditMatches)
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TH_Empty (1);
|
2019-09-29 18:44:40 +02:00
|
|
|
|
|
|
|
|
|
/***** The rest of columns *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TH (1,1,"LT",Txt_ROLES_SINGUL_Abc[Rol_TCH][Usr_SEX_UNKNOWN]);
|
|
|
|
|
HTM_TH (1,1,"LT",Txt_START_END_TIME[Gam_ORDER_BY_START_DATE]);
|
|
|
|
|
HTM_TH (1,1,"LT",Txt_START_END_TIME[Gam_ORDER_BY_END_DATE]);
|
|
|
|
|
HTM_TH (1,1,"LT",Txt_Match);
|
|
|
|
|
HTM_TH (1,1,"RT",Txt_Players);
|
|
|
|
|
HTM_TH (1,1,"CT",Txt_Status);
|
|
|
|
|
HTM_TH (1,1,"CT",Txt_Result);
|
2019-09-29 18:44:40 +02:00
|
|
|
|
|
|
|
|
|
/***** End row *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_End ();
|
2019-09-29 18:44:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-09-29 23:40:33 +02:00
|
|
|
|
/*********************** Check if I can edit matches *************************/
|
2019-09-29 18:44:40 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static bool Mch_CheckIfICanEditMatches (void)
|
|
|
|
|
{
|
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_NET:
|
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_SYS_ADM:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-09-25 00:42:13 +02:00
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-29 23:40:33 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-30 01:10:57 +02:00
|
|
|
|
/***************** Check if I can edit (remove/resume) a match ***************/
|
2019-09-29 23:40:33 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-30 01:10:57 +02:00
|
|
|
|
static bool Mch_CheckIfICanEditThisMatch (const struct Match *Match)
|
2019-09-29 23:40:33 +02:00
|
|
|
|
{
|
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_NET:
|
|
|
|
|
return (Match->UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod); // Only if I am the creator
|
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_SYS_ADM:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-25 09:29:44 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************************* Put a column for icons ****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesIcons (const struct Match *Match)
|
|
|
|
|
{
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
|
2019-09-25 09:29:44 +02:00
|
|
|
|
|
2019-09-29 17:33:39 +02:00
|
|
|
|
/***** Put icon to remove the match *****/
|
2019-09-30 01:10:57 +02:00
|
|
|
|
if (Mch_CheckIfICanEditThisMatch (Match))
|
2019-09-29 23:40:33 +02:00
|
|
|
|
{
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_SetCurrentGamCod (Match->GamCod); // Used to pass parameter
|
|
|
|
|
Mch_SetCurrentMchCod (Match->MchCod); // Used to pass parameter
|
2019-09-29 23:40:33 +02:00
|
|
|
|
Frm_StartForm (ActReqRemMch);
|
|
|
|
|
Mch_PutParamsEdit ();
|
|
|
|
|
Ico_PutIconRemove ();
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconRemovalNotAllowed ();
|
2019-09-25 09:29:44 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-09-25 09:29:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************* Put a column for teacher who created the match ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesAuthor (const struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Match author (teacher) *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
|
2019-09-25 09:29:44 +02:00
|
|
|
|
Usr_WriteAuthor1Line (Match->UsrCod,false);
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-09-25 09:29:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Put a column for match start and end times ****************/
|
|
|
|
|
/*****************************************************************************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesTimes (const struct Match *Match,unsigned UniqueId)
|
|
|
|
|
{
|
|
|
|
|
Dat_StartEndTime_t StartEndTime;
|
2019-11-01 22:53:39 +01:00
|
|
|
|
char *Id;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-15 20:02:34 +01:00
|
|
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
2019-09-25 00:42:13 +02:00
|
|
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
|
|
|
StartEndTime++)
|
|
|
|
|
{
|
2019-11-01 22:53:39 +01:00
|
|
|
|
if (asprintf (&Id,"mch_time_%u_%u",(unsigned) StartEndTime,UniqueId) < 0)
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
|
HTM_TD_Begin ("id=\"%s\" class=\"%s LT COLOR%u\"",
|
|
|
|
|
Id,
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Match->Status.Showing == Mch_END ? "DATE_RED" :
|
|
|
|
|
"DATE_GREEN",
|
2019-10-10 23:14:13 +02:00
|
|
|
|
Gbl.RowEvenOdd);
|
2019-11-01 23:35:55 +01:00
|
|
|
|
Dat_WriteLocalDateHMSFromUTC (Id,Match->TimeUTC[StartEndTime],
|
2019-11-02 12:10:58 +01:00
|
|
|
|
Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK,
|
2019-11-02 11:45:41 +01:00
|
|
|
|
true,true,true,0x7);
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-11-06 19:45:20 +01:00
|
|
|
|
free (Id);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Put a column for match title and grous ********************/
|
|
|
|
|
/*****************************************************************************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesTitleGrps (const struct Match *Match)
|
|
|
|
|
{
|
2019-12-05 19:54:28 +01:00
|
|
|
|
extern const char *Txt_Play;
|
|
|
|
|
extern const char *Txt_Resume;
|
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/***** Match title *****/
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Mch_SetCurrentMchCod (Match->MchCod); // Used to pass parameter
|
2019-12-05 19:54:28 +01:00
|
|
|
|
Frm_StartForm (Gbl.Usrs.Me.Role.Logged == Rol_STD ? ActJoiMch :
|
|
|
|
|
ActResMch);
|
|
|
|
|
Mch_PutParamsPlay ();
|
|
|
|
|
HTM_BUTTON_SUBMIT_Begin (Gbl.Usrs.Me.Role.Logged == Rol_STD ? Txt_Play :
|
|
|
|
|
Txt_Resume,
|
2019-12-13 18:22:59 +01:00
|
|
|
|
"BT_LINK LT ASG_TITLE",NULL);
|
2019-11-10 12:36:37 +01:00
|
|
|
|
HTM_Txt (Match->Title);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
|
|
|
|
Frm_EndForm ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/***** Groups whose students can answer this match *****/
|
|
|
|
|
if (Gbl.Crs.Grps.NumGrps)
|
|
|
|
|
Mch_GetAndWriteNamesOfGrpsAssociatedToMatch (Match);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-09-25 00:42:13 +02:00
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************* Get and write the names of the groups of a match **************/
|
|
|
|
|
/*****************************************************************************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
static void Mch_GetAndWriteNamesOfGrpsAssociatedToMatch (const struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Group;
|
|
|
|
|
extern const char *Txt_Groups;
|
|
|
|
|
extern const char *Txt_and;
|
|
|
|
|
extern const char *Txt_The_whole_course;
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
unsigned long NumRow;
|
|
|
|
|
unsigned long NumRows;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/***** Get groups associated to a match from database *****/
|
|
|
|
|
NumRows = DB_QuerySELECT (&mysql_res,"can not get groups of a match",
|
|
|
|
|
"SELECT crs_grp_types.GrpTypName,crs_grp.GrpName"
|
|
|
|
|
" FROM mch_groups,crs_grp,crs_grp_types"
|
|
|
|
|
" WHERE mch_groups.MchCod=%ld"
|
|
|
|
|
" AND mch_groups.GrpCod=crs_grp.GrpCod"
|
|
|
|
|
" AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod"
|
|
|
|
|
" ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName",
|
|
|
|
|
Match->MchCod);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/***** Write heading *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"ASG_GRP\"");
|
2020-01-11 15:22:02 +01:00
|
|
|
|
HTM_TxtColonNBSP (NumRows == 1 ? Txt_Group :
|
|
|
|
|
Txt_Groups);
|
2019-09-17 20:44:29 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/***** Write groups *****/
|
|
|
|
|
if (NumRows) // Groups found...
|
|
|
|
|
{
|
|
|
|
|
/* Get and write the group types and names */
|
|
|
|
|
for (NumRow = 0;
|
|
|
|
|
NumRow < NumRows;
|
|
|
|
|
NumRow++)
|
|
|
|
|
{
|
|
|
|
|
/* Get next group */
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
/* Write group type name and group name */
|
2019-11-11 10:59:24 +01:00
|
|
|
|
HTM_TxtF ("%s %s",row[0],row[1]);
|
2019-09-25 00:18:23 +02:00
|
|
|
|
|
2019-09-25 00:42:13 +02:00
|
|
|
|
if (NumRows >= 2)
|
|
|
|
|
{
|
|
|
|
|
if (NumRow == NumRows-2)
|
2019-11-11 00:15:44 +01:00
|
|
|
|
HTM_TxtF (" %s ",Txt_and);
|
2019-09-25 00:42:13 +02:00
|
|
|
|
if (NumRows >= 3)
|
|
|
|
|
if (NumRow < NumRows-2)
|
2019-11-10 16:41:47 +01:00
|
|
|
|
HTM_Txt (", ");
|
2019-09-25 00:42:13 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
2019-09-25 00:42:13 +02:00
|
|
|
|
else
|
2019-11-11 10:59:24 +01:00
|
|
|
|
HTM_TxtF ("%s %s",Txt_The_whole_course,Gbl.Hierarchy.Crs.ShrtName);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-25 00:42:13 +02:00
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-25 09:29:44 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************* Put a column for number of players **********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesNumPlayers (const struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Number of players who have answered any question in the match ******/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
|
2019-11-10 13:31:47 +01:00
|
|
|
|
HTM_Unsigned (Mch_GetNumUsrsWhoHaveAnswerMch (Match->MchCod));
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-09-25 09:29:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-25 00:28:57 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Put a column for match status ************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesStatus (const struct Match *Match,unsigned NumQsts)
|
2019-09-25 00:28:57 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Play;
|
|
|
|
|
extern const char *Txt_Resume;
|
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"DAT CT COLOR%u\"",Gbl.RowEvenOdd);
|
2019-09-25 00:28:57 +02:00
|
|
|
|
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.Showing != Mch_END) // Match not over
|
2019-10-23 20:07:56 +02:00
|
|
|
|
{
|
2019-09-25 00:28:57 +02:00
|
|
|
|
/* Current question index / total of questions */
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"DAT\"");
|
2019-11-11 00:15:44 +01:00
|
|
|
|
HTM_TxtF ("%u/%u",Match->Status.QstInd,NumQsts);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
2019-09-25 00:28:57 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* Icon to join match or resume match */
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Mch_SetCurrentMchCod (Match->MchCod); // Used to pass parameter
|
2019-12-05 19:54:28 +01:00
|
|
|
|
Lay_PutContextualLinkOnlyIcon (Gbl.Usrs.Me.Role.Logged == Rol_STD ? ActJoiMch :
|
|
|
|
|
ActResMch,
|
|
|
|
|
NULL,
|
|
|
|
|
Mch_PutParamsPlay,
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Match->Status.Showing == Mch_END ? "flag-checkered.svg" :
|
|
|
|
|
"play.svg",
|
2019-12-05 19:54:28 +01:00
|
|
|
|
Gbl.Usrs.Me.Role.Logged == Rol_STD ? Txt_Play :
|
|
|
|
|
Txt_Resume);
|
2019-09-25 00:28:57 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-09-25 00:28:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**************** Put a column for visibility of match result ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesResult (const struct Match *Match)
|
2019-09-25 00:28:57 +02:00
|
|
|
|
{
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"DAT CT COLOR%u\"",Gbl.RowEvenOdd);
|
2019-09-25 00:28:57 +02:00
|
|
|
|
|
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_STD:
|
2019-12-05 19:54:28 +01:00
|
|
|
|
Mch_ListOneOrMoreMatchesResultStd (Match);
|
2019-09-25 00:28:57 +02:00
|
|
|
|
break;
|
|
|
|
|
case Rol_NET:
|
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_SYS_ADM:
|
2019-12-05 19:54:28 +01:00
|
|
|
|
Mch_ListOneOrMoreMatchesResultTch (Match);
|
2019-09-25 00:28:57 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2019-12-05 19:54:28 +01:00
|
|
|
|
Rol_WrongRoleExit ();
|
2019-09-25 00:28:57 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-09-25 00:28:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ListOneOrMoreMatchesResultStd (const struct Match *Match)
|
|
|
|
|
{
|
2019-12-08 23:19:16 +01:00
|
|
|
|
extern const char *Txt_Hidden_results;
|
|
|
|
|
extern const char *Txt_Results;
|
2019-12-05 19:54:28 +01:00
|
|
|
|
|
|
|
|
|
/***** Is match result visible or hidden? *****/
|
|
|
|
|
if (Match->Status.ShowUsrResults)
|
|
|
|
|
{
|
|
|
|
|
/* Result is visible by me */
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_SetCurrentGamCod (Match->GamCod); // Used to pass parameter
|
|
|
|
|
Mch_SetCurrentMchCod (Match->MchCod); // Used to pass parameter
|
2019-12-09 11:09:12 +01:00
|
|
|
|
Lay_PutContextualLinkOnlyIcon (ActSeeMyMchResMch,McR_RESULTS_BOX_ID,
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Mch_PutParamsEdit,
|
|
|
|
|
"trophy.svg",
|
|
|
|
|
Txt_Results);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Result is forbidden to me */
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Ico_PutIconOff ("eye-slash.svg",Txt_Hidden_results);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Mch_ListOneOrMoreMatchesResultTch (const struct Match *Match)
|
|
|
|
|
{
|
2019-12-08 23:19:16 +01:00
|
|
|
|
extern const char *Txt_Visible_results;
|
|
|
|
|
extern const char *Txt_Hidden_results;
|
|
|
|
|
extern const char *Txt_Results;
|
2019-12-05 19:54:28 +01:00
|
|
|
|
|
|
|
|
|
/***** Can I edit match vivibility? *****/
|
|
|
|
|
if (Mch_CheckIfICanEditThisMatch (Match))
|
|
|
|
|
{
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_SetCurrentGamCod (Match->GamCod); // Used to pass parameter
|
|
|
|
|
Mch_SetCurrentMchCod (Match->MchCod); // Used to pass parameter
|
|
|
|
|
|
|
|
|
|
/* Show match results */
|
2019-12-09 11:09:12 +01:00
|
|
|
|
Lay_PutContextualLinkOnlyIcon (ActSeeAllMchResMch,McR_RESULTS_BOX_ID,
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Mch_PutParamsEdit,
|
|
|
|
|
"trophy.svg",
|
|
|
|
|
Txt_Results);
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/* I can edit visibility */
|
|
|
|
|
Lay_PutContextualLinkOnlyIcon (ActChgVisResMchUsr,NULL,
|
|
|
|
|
Mch_PutParamsEdit,
|
|
|
|
|
Match->Status.ShowUsrResults ? "eye.svg" :
|
|
|
|
|
"eye-slash.svg",
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Match->Status.ShowUsrResults ? Txt_Visible_results :
|
|
|
|
|
Txt_Hidden_results);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* I can not edit visibility */
|
|
|
|
|
Ico_PutIconOff (Match->Status.ShowUsrResults ? "eye.svg" :
|
|
|
|
|
"eye-slash.svg",
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Match->Status.ShowUsrResults ? Txt_Visible_results :
|
|
|
|
|
Txt_Hidden_results);
|
2019-12-05 19:54:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-25 21:58:12 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Toggle visibility of match results *********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_ToggleVisibilResultsMchUsr (void)
|
|
|
|
|
{
|
2019-09-29 22:38:32 +02:00
|
|
|
|
struct Game Game;
|
2019-09-25 21:58:12 +02:00
|
|
|
|
struct Match Match;
|
|
|
|
|
|
2019-09-29 22:38:32 +02:00
|
|
|
|
/***** Get and check parameters *****/
|
|
|
|
|
Mch_GetAndCheckParameters (&Game,&Match);
|
2019-09-25 21:58:12 +02:00
|
|
|
|
|
2019-09-30 01:10:57 +02:00
|
|
|
|
/***** Check if I have permission to change visibility *****/
|
|
|
|
|
if (!Mch_CheckIfICanEditThisMatch (&Match))
|
2019-10-26 01:56:36 +02:00
|
|
|
|
Lay_NoPermissionExit ();
|
2019-09-30 01:10:57 +02:00
|
|
|
|
|
2019-09-25 21:58:12 +02:00
|
|
|
|
/***** Toggle visibility of match results *****/
|
|
|
|
|
Match.Status.ShowUsrResults = !Match.Status.ShowUsrResults;
|
|
|
|
|
DB_QueryUPDATE ("can not toggle visibility of match results",
|
|
|
|
|
"UPDATE mch_matches"
|
|
|
|
|
" SET ShowUsrResults='%c'"
|
|
|
|
|
" WHERE MchCod=%ld",
|
|
|
|
|
Match.Status.ShowUsrResults ? 'Y' :
|
|
|
|
|
'N',
|
|
|
|
|
Match.MchCod);
|
|
|
|
|
|
|
|
|
|
/***** Show current game *****/
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_ShowOnlyOneGame (&Game,
|
2019-12-08 16:46:25 +01:00
|
|
|
|
false, // Do not list game questions
|
|
|
|
|
false); // Do not put form to start new match
|
2019-09-25 21:58:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Get game data from a database row **********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_GetMatchDataFromRow (MYSQL_RES *mysql_res,
|
|
|
|
|
struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
MYSQL_ROW row;
|
2019-09-22 19:50:24 +02:00
|
|
|
|
Dat_StartEndTime_t StartEndTime;
|
2019-10-22 23:42:22 +02:00
|
|
|
|
long LongNum;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Get match data *****/
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
/*
|
2019-09-25 21:58:12 +02:00
|
|
|
|
row[ 0] MchCod
|
|
|
|
|
row[ 1] GamCod
|
|
|
|
|
row[ 2] UsrCod
|
|
|
|
|
row[ 3] UNIX_TIMESTAMP(StartTime)
|
|
|
|
|
row[ 4] UNIX_TIMESTAMP(EndTime)
|
|
|
|
|
row[ 5] Title
|
2019-09-14 12:59:34 +02:00
|
|
|
|
*/
|
|
|
|
|
/***** Get match data *****/
|
|
|
|
|
/* Code of the match (row[0]) */
|
|
|
|
|
if ((Match->MchCod = Str_ConvertStrCodToLongCod (row[0])) <= 0)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong code of match.");
|
|
|
|
|
|
|
|
|
|
/* Code of the game (row[1]) */
|
|
|
|
|
if ((Match->GamCod = Str_ConvertStrCodToLongCod (row[1])) <= 0)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong code of game.");
|
|
|
|
|
|
|
|
|
|
/* Get match teacher (row[2]) */
|
|
|
|
|
Match->UsrCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
|
|
|
|
2019-09-22 19:50:24 +02:00
|
|
|
|
/* Get start/end times (row[3], row[4] hold start/end UTC times) */
|
2019-12-15 20:02:34 +01:00
|
|
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
2019-09-22 19:50:24 +02:00
|
|
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
|
|
|
StartEndTime++)
|
|
|
|
|
Match->TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[3 + StartEndTime]);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/* Get the title of the game (row[5]) */
|
|
|
|
|
if (row[5])
|
|
|
|
|
Str_Copy (Match->Title,row[5],
|
|
|
|
|
Gam_MAX_BYTES_TITLE);
|
|
|
|
|
else
|
|
|
|
|
Match->Title[0] = '\0';
|
|
|
|
|
|
|
|
|
|
/***** Get current match status *****/
|
|
|
|
|
/*
|
2019-09-25 21:58:12 +02:00
|
|
|
|
row[ 6] QstInd
|
|
|
|
|
row[ 7] QstCod
|
|
|
|
|
row[ 8] Showing
|
2019-12-12 18:24:23 +01:00
|
|
|
|
row[ 9] Countdown
|
|
|
|
|
row[10] NumCols
|
|
|
|
|
row[11] ShowQstResults
|
|
|
|
|
row[12] ShowUsrResults
|
2019-09-14 12:59:34 +02:00
|
|
|
|
*/
|
|
|
|
|
/* Current question index (row[6]) */
|
|
|
|
|
Match->Status.QstInd = Gam_GetQstIndFromStr (row[6]);
|
|
|
|
|
|
|
|
|
|
/* Current question code (row[7]) */
|
|
|
|
|
Match->Status.QstCod = Str_ConvertStrCodToLongCod (row[7]);
|
|
|
|
|
|
2019-09-25 21:58:12 +02:00
|
|
|
|
/* Get what to show (stem, answers, results) (row(8)) */
|
|
|
|
|
Match->Status.Showing = Mch_GetShowingFromStr (row[8]);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-12 18:24:23 +01:00
|
|
|
|
/* Get countdown (row[9]) */
|
|
|
|
|
Match->Status.Countdown = Str_ConvertStrCodToLongCod (row[9]);
|
|
|
|
|
|
|
|
|
|
/* Get number of columns (row[10]) */
|
|
|
|
|
LongNum = Str_ConvertStrCodToLongCod (row[10]);
|
2019-10-22 23:42:22 +02:00
|
|
|
|
Match->Status.NumCols = (LongNum <= 1 ) ? 1 :
|
|
|
|
|
((LongNum >= Mch_MAX_COLS) ? Mch_MAX_COLS :
|
|
|
|
|
(unsigned) LongNum);
|
|
|
|
|
|
2019-12-12 18:24:23 +01:00
|
|
|
|
/* Get whether to show question results or not (row(11)) */
|
|
|
|
|
Match->Status.ShowQstResults = (row[11][0] == 'Y');
|
2019-09-25 21:58:12 +02:00
|
|
|
|
|
2019-12-12 18:24:23 +01:00
|
|
|
|
/* Get whether to show user results or not (row(12)) */
|
|
|
|
|
Match->Status.ShowUsrResults = (row[12][0] == 'Y');
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Get whether the match is being played or not *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.Showing == Mch_END) // Match over
|
2019-09-17 15:42:41 +02:00
|
|
|
|
Match->Status.Playing = false;
|
2019-12-10 21:52:22 +01:00
|
|
|
|
else // Match not over
|
2019-09-17 15:42:41 +02:00
|
|
|
|
Match->Status.Playing = Mch_GetIfMatchIsBeingPlayed (Match->MchCod);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Get parameter with what is being shown *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static Mch_Showing_t Mch_GetShowingFromStr (const char *Str)
|
|
|
|
|
{
|
|
|
|
|
Mch_Showing_t Showing;
|
|
|
|
|
|
2019-12-12 18:24:23 +01:00
|
|
|
|
for (Showing = (Mch_Showing_t) 0;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Showing <= (Mch_Showing_t) (Mch_NUM_SHOWING - 1);
|
|
|
|
|
Showing++)
|
|
|
|
|
if (!strcmp (Str,Mch_ShowingStringsDB[Showing]))
|
|
|
|
|
return Showing;
|
|
|
|
|
|
|
|
|
|
return (Mch_Showing_t) Mch_SHOWING_DEFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************** Request the removal of a match (game instance) ***************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
void Mch_RequestRemoveMatch (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Do_you_really_want_to_remove_the_match_X;
|
|
|
|
|
extern const char *Txt_Remove_match;
|
2019-09-29 22:38:32 +02:00
|
|
|
|
struct Game Game;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
struct Match Match;
|
|
|
|
|
|
2019-09-29 22:38:32 +02:00
|
|
|
|
/***** Get and check parameters *****/
|
|
|
|
|
Mch_GetAndCheckParameters (&Game,&Match);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Show question and button to remove question *****/
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_SetCurrentGamCod (Match.GamCod); // Used to pass parameter
|
|
|
|
|
Mch_SetCurrentMchCod (Match.MchCod); // Used to pass parameter
|
2019-09-29 22:38:32 +02:00
|
|
|
|
Ale_ShowAlertAndButton (ActRemMch,NULL,NULL,Mch_PutParamsEdit,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Btn_REMOVE_BUTTON,Txt_Remove_match,
|
|
|
|
|
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_match_X,
|
|
|
|
|
Match.Title);
|
|
|
|
|
|
|
|
|
|
/***** Show current game *****/
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_ShowOnlyOneGame (&Game,
|
2019-12-08 16:46:25 +01:00
|
|
|
|
false, // Do not list game questions
|
|
|
|
|
false); // Do not put form to start new match
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Remove a match (game instance) ***********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
void Mch_RemoveMatch (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Match_X_removed;
|
2019-09-27 20:00:47 +02:00
|
|
|
|
struct Game Game;
|
2019-09-29 22:38:32 +02:00
|
|
|
|
struct Match Match;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-29 22:38:32 +02:00
|
|
|
|
/***** Get and check parameters *****/
|
|
|
|
|
Mch_GetAndCheckParameters (&Game,&Match);
|
2019-09-27 20:00:47 +02:00
|
|
|
|
|
2019-09-29 23:40:33 +02:00
|
|
|
|
/***** Check if I can remove this match *****/
|
2019-09-30 01:10:57 +02:00
|
|
|
|
if (!Mch_CheckIfICanEditThisMatch (&Match))
|
2019-10-26 01:56:36 +02:00
|
|
|
|
Lay_NoPermissionExit ();
|
2019-09-29 23:40:33 +02:00
|
|
|
|
|
2019-09-27 20:00:47 +02:00
|
|
|
|
/***** Remove the match from all database tables *****/
|
|
|
|
|
Mch_RemoveMatchFromAllTables (Match.MchCod);
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Write message *****/
|
|
|
|
|
Ale_ShowAlert (Ale_SUCCESS,Txt_Match_X_removed,
|
|
|
|
|
Match.Title);
|
|
|
|
|
|
|
|
|
|
/***** Show current game *****/
|
2019-12-08 23:19:16 +01:00
|
|
|
|
Gam_ShowOnlyOneGame (&Game,
|
2019-12-08 16:46:25 +01:00
|
|
|
|
false, // Do not list game questions
|
|
|
|
|
false); // Do not put form to start new match
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 20:00:47 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Remove match from all tables *************************/
|
|
|
|
|
/*****************************************************************************/
|
2019-09-29 23:13:20 +02:00
|
|
|
|
/*
|
|
|
|
|
mysql> SELECT table_name FROM information_schema.tables WHERE table_name LIKE 'mch%';
|
|
|
|
|
*/
|
2019-09-27 20:00:47 +02:00
|
|
|
|
static void Mch_RemoveMatchFromAllTables (long MchCod)
|
|
|
|
|
{
|
2019-09-28 01:12:53 +02:00
|
|
|
|
/***** Remove match from secondary tables *****/
|
2019-09-29 23:13:20 +02:00
|
|
|
|
Mch_RemoveMatchFromTable (MchCod,"mch_players");
|
|
|
|
|
Mch_RemoveMatchFromTable (MchCod,"mch_playing");
|
|
|
|
|
Mch_RemoveMatchFromTable (MchCod,"mch_results");
|
|
|
|
|
Mch_RemoveMatchFromTable (MchCod,"mch_answers");
|
|
|
|
|
Mch_RemoveMatchFromTable (MchCod,"mch_times");
|
|
|
|
|
Mch_RemoveMatchFromTable (MchCod,"mch_groups");
|
|
|
|
|
Mch_RemoveMatchFromTable (MchCod,"mch_indexes");
|
2019-09-28 01:12:53 +02:00
|
|
|
|
|
|
|
|
|
/***** Remove match from main table *****/
|
|
|
|
|
DB_QueryDELETE ("can not remove match",
|
|
|
|
|
"DELETE FROM mch_matches WHERE MchCod=%ld",
|
|
|
|
|
MchCod);
|
2019-09-27 20:00:47 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-29 23:13:20 +02:00
|
|
|
|
static void Mch_RemoveMatchFromTable (long MchCod,const char *TableName)
|
|
|
|
|
{
|
|
|
|
|
/***** Remove match from secondary table *****/
|
|
|
|
|
DB_QueryDELETE ("can not remove match from table",
|
|
|
|
|
"DELETE FROM %s WHERE MchCod=%ld",
|
|
|
|
|
TableName,
|
|
|
|
|
MchCod);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 21:45:53 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Remove match in game from all tables *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-28 01:12:53 +02:00
|
|
|
|
void Mch_RemoveMatchesInGameFromAllTables (long GamCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Remove matches from secondary tables *****/
|
2019-09-29 23:13:20 +02:00
|
|
|
|
Mch_RemoveMatchesInGameFromTable (GamCod,"mch_players");
|
|
|
|
|
Mch_RemoveMatchesInGameFromTable (GamCod,"mch_playing");
|
|
|
|
|
Mch_RemoveMatchesInGameFromTable (GamCod,"mch_results");
|
|
|
|
|
Mch_RemoveMatchesInGameFromTable (GamCod,"mch_answers");
|
|
|
|
|
Mch_RemoveMatchesInGameFromTable (GamCod,"mch_times");
|
|
|
|
|
Mch_RemoveMatchesInGameFromTable (GamCod,"mch_groups");
|
|
|
|
|
Mch_RemoveMatchesInGameFromTable (GamCod,"mch_indexes");
|
2019-09-28 01:12:53 +02:00
|
|
|
|
|
|
|
|
|
/***** Remove matches from main table *****/
|
|
|
|
|
DB_QueryDELETE ("can not remove matches of a game",
|
|
|
|
|
"DELETE FROM mch_matches WHERE GamCod=%ld",
|
|
|
|
|
GamCod);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-29 23:13:20 +02:00
|
|
|
|
static void Mch_RemoveMatchesInGameFromTable (long GamCod,const char *TableName)
|
|
|
|
|
{
|
|
|
|
|
/***** Remove matches in game from secondary table *****/
|
|
|
|
|
DB_QueryDELETE ("can not remove matches of a game from table",
|
|
|
|
|
"DELETE FROM %s"
|
|
|
|
|
" USING mch_matches,%s"
|
|
|
|
|
" WHERE mch_matches.GamCod=%ld"
|
|
|
|
|
" AND mch_matches.MchCod=%s.MchCod",
|
|
|
|
|
TableName,
|
|
|
|
|
TableName,
|
|
|
|
|
GamCod,
|
|
|
|
|
TableName);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-28 01:12:53 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************* Remove match in course from all tables ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_RemoveMatchInCourseFromAllTables (long CrsCod)
|
2019-09-27 21:45:53 +02:00
|
|
|
|
{
|
2019-09-28 01:12:53 +02:00
|
|
|
|
/***** Remove matches from secondary tables *****/
|
2019-09-29 23:13:20 +02:00
|
|
|
|
Mch_RemoveMatchInCourseFromTable (CrsCod,"mch_players");
|
|
|
|
|
Mch_RemoveMatchInCourseFromTable (CrsCod,"mch_playing");
|
|
|
|
|
Mch_RemoveMatchInCourseFromTable (CrsCod,"mch_results");
|
|
|
|
|
Mch_RemoveMatchInCourseFromTable (CrsCod,"mch_answers");
|
|
|
|
|
Mch_RemoveMatchInCourseFromTable (CrsCod,"mch_times");
|
|
|
|
|
Mch_RemoveMatchInCourseFromTable (CrsCod,"mch_groups");
|
|
|
|
|
Mch_RemoveMatchInCourseFromTable (CrsCod,"mch_indexes");
|
2019-09-28 01:12:53 +02:00
|
|
|
|
|
|
|
|
|
/***** Remove matches from main table *****/
|
2019-10-04 14:57:04 +02:00
|
|
|
|
DB_QueryDELETE ("can not remove matches of a course",
|
|
|
|
|
"DELETE FROM mch_matches"
|
2019-09-28 01:12:53 +02:00
|
|
|
|
" USING gam_games,mch_matches"
|
|
|
|
|
" WHERE gam_games.CrsCod=%ld"
|
|
|
|
|
" AND gam_games.GamCod=mch_matches.GamCod",
|
|
|
|
|
CrsCod);
|
2019-09-27 21:45:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-29 23:13:20 +02:00
|
|
|
|
static void Mch_RemoveMatchInCourseFromTable (long CrsCod,const char *TableName)
|
2019-09-27 21:45:53 +02:00
|
|
|
|
{
|
2019-09-29 23:13:20 +02:00
|
|
|
|
/***** Remove matches in course from secondary table *****/
|
|
|
|
|
DB_QueryDELETE ("can not remove matches of a course from table",
|
2019-09-27 21:45:53 +02:00
|
|
|
|
"DELETE FROM %s"
|
2019-09-29 23:13:20 +02:00
|
|
|
|
" USING gam_games,mch_matches,%s"
|
|
|
|
|
" WHERE gam_games.CrsCod=%ld"
|
|
|
|
|
" AND gam_games.GamCod=mch_matches.GamCod"
|
2019-09-27 21:45:53 +02:00
|
|
|
|
" AND mch_matches.MchCod=%s.MchCod",
|
|
|
|
|
TableName,
|
|
|
|
|
TableName,
|
2019-09-29 23:13:20 +02:00
|
|
|
|
CrsCod,
|
2019-09-27 21:45:53 +02:00
|
|
|
|
TableName);
|
2019-09-27 20:00:47 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-28 01:12:53 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-29 23:13:20 +02:00
|
|
|
|
/***************** Remove user from secondary match tables *******************/
|
2019-09-28 01:12:53 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 23:13:20 +02:00
|
|
|
|
void Mch_RemoveUsrFromMatchTablesInCrs (long UsrCod,long CrsCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Remove student from secondary tables *****/
|
|
|
|
|
Mch_RemoveUsrMchResultsInCrs (UsrCod,CrsCod,"mch_players");
|
|
|
|
|
Mch_RemoveUsrMchResultsInCrs (UsrCod,CrsCod,"mch_results");
|
|
|
|
|
Mch_RemoveUsrMchResultsInCrs (UsrCod,CrsCod,"mch_answers");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Mch_RemoveUsrMchResultsInCrs (long UsrCod,long CrsCod,const char *TableName)
|
2019-09-28 01:12:53 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Remove matches in course from secondary table *****/
|
2019-09-29 23:13:20 +02:00
|
|
|
|
DB_QueryDELETE ("can not remove matches of a user from table",
|
2019-09-28 01:12:53 +02:00
|
|
|
|
"DELETE FROM %s"
|
|
|
|
|
" USING gam_games,mch_matches,%s"
|
|
|
|
|
" WHERE gam_games.CrsCod=%ld"
|
|
|
|
|
" AND gam_games.GamCod=mch_matches.GamCod"
|
2019-09-29 23:13:20 +02:00
|
|
|
|
" AND mch_matches.MchCod=%s.MchCod"
|
|
|
|
|
" AND %s.UsrCod=%ld",
|
2019-09-28 01:12:53 +02:00
|
|
|
|
TableName,
|
|
|
|
|
TableName,
|
|
|
|
|
CrsCod,
|
2019-09-29 23:13:20 +02:00
|
|
|
|
TableName,
|
|
|
|
|
TableName,
|
|
|
|
|
UsrCod);
|
2019-09-28 01:12:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-29 17:33:39 +02:00
|
|
|
|
/*********************** Params used to edit a match *************************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-30 01:10:57 +02:00
|
|
|
|
void Mch_PutParamsEdit (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-09-29 22:38:32 +02:00
|
|
|
|
Gam_PutParams ();
|
|
|
|
|
Mch_PutParamsPlay ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************** Params used to edit a match *************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_PutParamsPlay (void)
|
|
|
|
|
{
|
2019-12-08 23:19:16 +01:00
|
|
|
|
long CurrentMchCod = Mch_GetCurrentMchCod ();
|
2019-09-29 22:38:32 +02:00
|
|
|
|
|
|
|
|
|
if (CurrentMchCod > 0)
|
|
|
|
|
Mch_PutParamMchCod (CurrentMchCod);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Write parameter with code of match **********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-30 01:10:57 +02:00
|
|
|
|
static void Mch_PutParamMchCod (long MchCod)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-11-03 13:19:32 +01:00
|
|
|
|
Par_PutHiddenParamLong (NULL,"MchCod",MchCod);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-29 22:38:32 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************************** Get and check parameters *************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_GetAndCheckParameters (struct Game *Game,struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Get parameters *****/
|
|
|
|
|
/* Get parameters of game */
|
|
|
|
|
if ((Game->GamCod = Gam_GetParams ()) == -1L)
|
|
|
|
|
Lay_ShowErrorAndExit ("Code of game is missing.");
|
2019-11-28 10:15:39 +01:00
|
|
|
|
Grp_GetParamWhichGrps ();
|
2019-09-29 22:38:32 +02:00
|
|
|
|
Gam_GetDataOfGameByCod (Game);
|
|
|
|
|
|
|
|
|
|
/* Get match code */
|
|
|
|
|
if ((Match->MchCod = Mch_GetParamMchCod ()) == -1L)
|
|
|
|
|
Lay_ShowErrorAndExit ("Code of match is missing.");
|
|
|
|
|
Mch_GetDataOfMatchByCod (Match);
|
|
|
|
|
|
|
|
|
|
/***** Ensure parameters are correct *****/
|
|
|
|
|
if (Game->GamCod != Match->GamCod)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong game code.");
|
|
|
|
|
if (Game->CrsCod != Gbl.Hierarchy.Crs.CrsCod)
|
|
|
|
|
Lay_ShowErrorAndExit ("Match does not belong to this course.");
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************* Get parameter with code of match **********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-28 02:31:42 +02:00
|
|
|
|
long Mch_GetParamMchCod (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Get code of match *****/
|
|
|
|
|
return Par_GetParToLong ("MchCod");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****** Put a big button to play match (start a new match) as a teacher ******/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_PutFormNewMatch (const struct Game *Game)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-10-03 22:12:31 +02:00
|
|
|
|
extern const char *Hlp_ASSESSMENT_Games_matches;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
extern const char *Txt_New_match;
|
|
|
|
|
extern const char *Txt_Title;
|
|
|
|
|
extern const char *Txt_Play;
|
|
|
|
|
|
|
|
|
|
/***** Start section for a new match *****/
|
2019-10-26 01:56:36 +02:00
|
|
|
|
HTM_SECTION_Begin (Mch_NEW_MATCH_SECTION_ID);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-20 22:00:28 +02:00
|
|
|
|
/***** Begin form *****/
|
2019-09-29 21:33:27 +02:00
|
|
|
|
Frm_StartForm (ActNewMch);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Gam_PutParamGameCod (Game->GamCod);
|
|
|
|
|
Gam_PutParamQstInd (0); // Start by first question in game
|
|
|
|
|
|
2019-10-26 02:19:42 +02:00
|
|
|
|
/***** Begin box and table *****/
|
2019-11-25 23:18:08 +01:00
|
|
|
|
Box_BoxTableBegin (NULL,Txt_New_match,NULL,
|
2019-10-03 22:12:31 +02:00
|
|
|
|
Hlp_ASSESSMENT_Games_matches,Box_NOT_CLOSABLE,2);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Match title *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-10-07 17:36:41 +02:00
|
|
|
|
|
2019-12-27 21:10:39 +01:00
|
|
|
|
/* Label */
|
2019-12-27 15:45:19 +01:00
|
|
|
|
Frm_LabelColumn ("RT","Title",Txt_Title);
|
2019-10-07 17:36:41 +02:00
|
|
|
|
|
2019-12-27 21:10:39 +01:00
|
|
|
|
/* Data */
|
2019-12-26 22:29:04 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
2019-11-04 12:25:48 +01:00
|
|
|
|
HTM_INPUT_TEXT ("Title",Gam_MAX_CHARS_TITLE,Game->Title,false,
|
2019-11-12 15:41:58 +01:00
|
|
|
|
"id=\"Title\" size=\"45\" required=\"required\"");
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-10-07 17:36:41 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Groups *****/
|
|
|
|
|
Mch_ShowLstGrpsToCreateMatch ();
|
|
|
|
|
|
|
|
|
|
/***** End table *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TABLE_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-11-18 15:48:46 +01:00
|
|
|
|
/***** Put icon to submit the form *****/
|
|
|
|
|
HTM_INPUT_IMAGE (Cfg_URL_ICON_PUBLIC,"play.svg",
|
|
|
|
|
Txt_Play,"CONTEXT_OPT ICO_HIGHLIGHT ICO64x64");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** End box *****/
|
2019-10-25 22:48:34 +02:00
|
|
|
|
Box_BoxEnd ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** End form *****/
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
|
|
|
|
|
/***** End section for a new match *****/
|
2019-10-26 01:56:36 +02:00
|
|
|
|
HTM_SECTION_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Show list of groups to create a new match *****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ShowLstGrpsToCreateMatch (void)
|
|
|
|
|
{
|
|
|
|
|
extern const char *The_ClassFormInBox[The_NUM_THEMES];
|
|
|
|
|
extern const char *Txt_Groups;
|
|
|
|
|
extern const char *Txt_The_whole_course;
|
|
|
|
|
unsigned NumGrpTyp;
|
|
|
|
|
|
|
|
|
|
/***** Get list of groups types and groups in this course *****/
|
|
|
|
|
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
|
|
|
|
|
|
|
|
|
|
if (Gbl.Crs.Grps.GrpTypes.Num)
|
|
|
|
|
{
|
2019-10-26 02:19:42 +02:00
|
|
|
|
/***** Begin box and table *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-10-07 17:36:41 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
|
2019-11-11 10:59:24 +01:00
|
|
|
|
HTM_TxtF ("%s:",Txt_Groups);
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-10-07 17:36:41 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
2019-11-25 23:18:08 +01:00
|
|
|
|
Box_BoxTableBegin ("95%",NULL,NULL,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
NULL,Box_NOT_CLOSABLE,0);
|
|
|
|
|
|
|
|
|
|
/***** First row: checkbox to select the whole course *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-12-26 22:29:04 +01:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("colspan=\"7\" class=\"DAT LM\"");
|
2019-11-03 10:41:31 +01:00
|
|
|
|
HTM_LABEL_Begin (NULL);
|
2019-11-04 20:41:35 +01:00
|
|
|
|
HTM_INPUT_CHECKBOX ("WholeCrs",true,
|
|
|
|
|
"id=\"WholeCrs\" value=\"Y\" checked=\"checked\""
|
|
|
|
|
" onclick=\"uncheckChildren(this,'GrpCods')\"");
|
2019-11-11 10:59:24 +01:00
|
|
|
|
HTM_TxtF ("%s %s",Txt_The_whole_course,Gbl.Hierarchy.Crs.ShrtName);
|
2019-11-02 12:59:31 +01:00
|
|
|
|
HTM_LABEL_End ();
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-10-07 17:36:41 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** List the groups for each group type *****/
|
|
|
|
|
for (NumGrpTyp = 0;
|
|
|
|
|
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
|
|
|
|
|
NumGrpTyp++)
|
|
|
|
|
if (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps)
|
|
|
|
|
Grp_ListGrpsToEditAsgAttSvyMch (&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp],
|
|
|
|
|
-1L, // -1 means "New match"
|
|
|
|
|
Grp_MATCH);
|
|
|
|
|
|
|
|
|
|
/***** End table and box *****/
|
2019-11-25 23:18:08 +01:00
|
|
|
|
Box_BoxTableEnd ();
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
HTM_TR_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Free list of groups types and groups in this course *****/
|
|
|
|
|
Grp_FreeListGrpTypesAndGrps ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************* Create a new match (by a teacher) *********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_CreateNewMatchTch (void)
|
|
|
|
|
{
|
|
|
|
|
long GamCod;
|
|
|
|
|
char Title[Gam_MAX_BYTES_TITLE + 1];
|
|
|
|
|
|
|
|
|
|
/***** Get form parameters *****/
|
|
|
|
|
/* Get match code */
|
|
|
|
|
if ((GamCod = Gam_GetParamGameCod ()) == -1L)
|
|
|
|
|
Lay_ShowErrorAndExit ("Code of game is missing.");
|
|
|
|
|
|
|
|
|
|
/* Get match title */
|
|
|
|
|
Par_GetParToText ("Title",Title,Gam_MAX_BYTES_TITLE);
|
|
|
|
|
|
|
|
|
|
/* Get groups for this games */
|
|
|
|
|
Grp_GetParCodsSeveralGrps ();
|
|
|
|
|
|
|
|
|
|
/***** Create a new match *****/
|
|
|
|
|
Gbl.Games.MchCodBeingPlayed = Mch_CreateMatch (GamCod,Title);
|
|
|
|
|
|
|
|
|
|
/***** Free memory for list of selected groups *****/
|
|
|
|
|
Grp_FreeListCodSelectedGrps ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******* Show button to actually start / resume a match (by a teacher) *******/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
void Mch_ResumeMatch (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
2019-10-01 21:18:53 +02:00
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
2019-09-30 01:10:57 +02:00
|
|
|
|
/***** Check if I have permission to resume match *****/
|
|
|
|
|
if (!Mch_CheckIfICanEditThisMatch (&Match))
|
2019-10-26 01:56:36 +02:00
|
|
|
|
Lay_NoPermissionExit ();
|
2019-09-30 01:10:57 +02:00
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ShowMatchStatusForTch (&Match);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Create a new match in a game *************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static long Mch_CreateMatch (long GamCod,char Title[Gam_MAX_BYTES_TITLE + 1])
|
|
|
|
|
{
|
|
|
|
|
long MchCod;
|
|
|
|
|
|
|
|
|
|
/***** Insert this new match into database *****/
|
|
|
|
|
MchCod = DB_QueryINSERTandReturnCode ("can not create match",
|
2019-09-17 23:35:30 +02:00
|
|
|
|
"INSERT mch_matches "
|
|
|
|
|
"(GamCod,UsrCod,StartTime,EndTime,Title,"
|
2019-12-12 18:24:23 +01:00
|
|
|
|
"QstInd,QstCod,Showing,Countdown,"
|
|
|
|
|
"NumCols,ShowQstResults,ShowUsrResults)"
|
2019-09-17 23:35:30 +02:00
|
|
|
|
" VALUES "
|
|
|
|
|
"(%ld," // GamCod
|
2019-09-14 12:59:34 +02:00
|
|
|
|
"%ld," // UsrCod
|
|
|
|
|
"NOW()," // StartTime
|
|
|
|
|
"NOW()," // EndTime
|
|
|
|
|
"'%s'," // Title
|
|
|
|
|
"0," // QstInd: Match has not started, so not the first question yet
|
|
|
|
|
"-1," // QstCod: Non-existent question
|
2019-09-25 21:58:12 +02:00
|
|
|
|
"'%s'," // Showing: What is being shown
|
2019-12-12 18:24:23 +01:00
|
|
|
|
"-1," // Countdown: No countdown
|
2019-10-22 23:42:22 +02:00
|
|
|
|
"%u," // NumCols: Number of columns in answers
|
2019-09-26 01:25:43 +02:00
|
|
|
|
"'N'," // ShowQstResults: Don't show question results initially
|
2019-09-25 21:58:12 +02:00
|
|
|
|
"'N')", // ShowUsrResults: Don't show user results initially
|
2019-09-14 12:59:34 +02:00
|
|
|
|
GamCod,
|
|
|
|
|
Gbl.Usrs.Me.UsrDat.UsrCod, // Game creator
|
|
|
|
|
Title,
|
2019-10-22 23:42:22 +02:00
|
|
|
|
Mch_ShowingStringsDB[Mch_SHOWING_DEFAULT],
|
|
|
|
|
Mch_NUM_COLS_DEFAULT);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-23 21:39:54 +02:00
|
|
|
|
/***** Create indexes for answers *****/
|
|
|
|
|
Mch_CreateIndexes (GamCod,MchCod);
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Create groups associated to the match *****/
|
|
|
|
|
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
|
|
|
|
|
Mch_CreateGrps (MchCod);
|
|
|
|
|
|
|
|
|
|
return MchCod;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-23 21:39:54 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************** Create indexes for a match **************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Everytime a new match is created,
|
|
|
|
|
the answers of each shufflable question are shuffled.
|
|
|
|
|
The shuffling is stored in a table of indexes
|
|
|
|
|
that will be read when showing a match */
|
|
|
|
|
|
|
|
|
|
static void Mch_CreateIndexes (long GamCod,long MchCod)
|
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
unsigned NumQsts;
|
|
|
|
|
unsigned NumQst;
|
|
|
|
|
long QstCod;
|
|
|
|
|
long LongNum;
|
|
|
|
|
unsigned QstInd;
|
|
|
|
|
Tst_AnswerType_t AnswerType;
|
|
|
|
|
bool Shuffle;
|
|
|
|
|
|
|
|
|
|
/***** Get questions of the game *****/
|
|
|
|
|
NumQsts = (unsigned)
|
|
|
|
|
DB_QuerySELECT (&mysql_res,"can not get questions of a game",
|
|
|
|
|
"SELECT gam_questions.QstCod," // row[0]
|
|
|
|
|
"gam_questions.QstInd," // row[1]
|
2019-09-24 01:41:51 +02:00
|
|
|
|
"tst_questions.AnsType," // row[2]
|
2019-09-23 21:39:54 +02:00
|
|
|
|
"tst_questions.Shuffle" // row[3]
|
|
|
|
|
" FROM gam_questions,tst_questions"
|
|
|
|
|
" WHERE gam_questions.GamCod=%ld"
|
|
|
|
|
" AND gam_questions.QstCod=tst_questions.QstCod"
|
|
|
|
|
" ORDER BY gam_questions.QstInd",
|
|
|
|
|
GamCod);
|
|
|
|
|
|
|
|
|
|
/***** For each question in game... *****/
|
|
|
|
|
for (NumQst = 0;
|
|
|
|
|
NumQst < NumQsts;
|
|
|
|
|
NumQst++)
|
|
|
|
|
{
|
|
|
|
|
/***** Get question data *****/
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
|
|
|
|
|
/* Get question code (row[0]) */
|
|
|
|
|
if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong code of question.");
|
|
|
|
|
|
|
|
|
|
/* Get question index (row[1]) */
|
|
|
|
|
if ((LongNum = Str_ConvertStrCodToLongCod (row[1])) < 0)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong question index.");
|
|
|
|
|
QstInd = (unsigned) LongNum;
|
|
|
|
|
|
|
|
|
|
/* Get answer type (row[2]) */
|
|
|
|
|
AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[2]);
|
|
|
|
|
if (AnswerType != Tst_ANS_UNIQUE_CHOICE)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong answer type.");
|
|
|
|
|
|
|
|
|
|
/* Get shuffle (row[3]) */
|
|
|
|
|
Shuffle = (row[3][0] == 'Y');
|
|
|
|
|
|
|
|
|
|
/***** Reorder answer *****/
|
|
|
|
|
Mch_ReorderAnswer (MchCod,QstInd,QstCod,Shuffle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************* Reorder answers of a match question *********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
|
|
|
|
|
long QstCod,bool Shuffle)
|
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
unsigned NumAnss;
|
|
|
|
|
unsigned NumAns;
|
|
|
|
|
long LongNum;
|
|
|
|
|
unsigned AnsInd;
|
2019-11-08 01:10:32 +01:00
|
|
|
|
char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
|
2019-09-23 21:39:54 +02:00
|
|
|
|
char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1];
|
|
|
|
|
|
|
|
|
|
/***** Initialize list of answers to empty string *****/
|
|
|
|
|
StrAnswersOneQst[0] = '\0';
|
|
|
|
|
|
|
|
|
|
/***** Get questions of the game *****/
|
|
|
|
|
NumAnss = (unsigned)
|
|
|
|
|
DB_QuerySELECT (&mysql_res,"can not get questions of a game",
|
|
|
|
|
"SELECT AnsInd" // row[0]
|
|
|
|
|
" FROM tst_answers"
|
2019-09-24 01:41:51 +02:00
|
|
|
|
" WHERE QstCod=%ld"
|
2019-09-23 21:39:54 +02:00
|
|
|
|
" ORDER BY %s",
|
|
|
|
|
QstCod,
|
2019-09-24 01:41:51 +02:00
|
|
|
|
Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order
|
2019-09-23 21:39:54 +02:00
|
|
|
|
"AnsInd");
|
|
|
|
|
|
|
|
|
|
/***** For each answer in question... *****/
|
|
|
|
|
for (NumAns = 0;
|
|
|
|
|
NumAns < NumAnss;
|
|
|
|
|
NumAns++)
|
|
|
|
|
{
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
|
|
|
|
|
/* Get answer index (row[0]) */
|
|
|
|
|
if ((LongNum = Str_ConvertStrCodToLongCod (row[0])) < 0)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong answer index.");
|
|
|
|
|
AnsInd = (unsigned) LongNum;
|
2019-09-24 01:41:51 +02:00
|
|
|
|
snprintf (StrOneAnswer,sizeof (StrOneAnswer),
|
|
|
|
|
"%u",AnsInd);
|
2019-09-23 21:39:54 +02:00
|
|
|
|
|
|
|
|
|
/* Concatenate answer index to list of answers */
|
|
|
|
|
if (NumAns)
|
|
|
|
|
Str_Concat (StrAnswersOneQst,",",
|
|
|
|
|
Tst_MAX_BYTES_ANSWERS_ONE_QST);
|
|
|
|
|
Str_Concat (StrAnswersOneQst,StrOneAnswer,
|
|
|
|
|
Tst_MAX_BYTES_ANSWERS_ONE_QST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
|
|
|
|
|
/***** Create entry for this question in table of match indexes *****/
|
|
|
|
|
DB_QueryINSERT ("can not create match indexes",
|
|
|
|
|
"INSERT INTO mch_indexes"
|
|
|
|
|
" (MchCod,QstInd,Indexes)"
|
|
|
|
|
" VALUES"
|
|
|
|
|
" (%ld,%u,'%s')",
|
|
|
|
|
MchCod,QstInd,StrAnswersOneQst);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 01:41:51 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Get indexes for a question from database ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_GetIndexes (long MchCod,unsigned QstInd,
|
|
|
|
|
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION])
|
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1];
|
|
|
|
|
|
|
|
|
|
/***** Get indexes for a question from database *****/
|
|
|
|
|
if (!DB_QuerySELECT (&mysql_res,"can not get data of a question",
|
|
|
|
|
"SELECT Indexes" // row[0]
|
|
|
|
|
" FROM mch_indexes"
|
|
|
|
|
" WHERE MchCod=%ld AND QstInd=%u",
|
|
|
|
|
MchCod,QstInd))
|
|
|
|
|
Lay_ShowErrorAndExit ("No indexes found for a question.");
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
|
|
|
|
|
/* Get indexes (row[0]) */
|
|
|
|
|
Str_Copy (StrIndexesOneQst,row[0],
|
|
|
|
|
Tst_MAX_BYTES_INDEXES_ONE_QST);
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
|
|
|
|
|
/***** Get indexes from string *****/
|
|
|
|
|
Par_ReplaceCommaBySeparatorMultiple (StrIndexesOneQst);
|
|
|
|
|
Tst_GetIndexesFromStr (StrIndexesOneQst,Indexes);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************* Create groups associated to a match *********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_CreateGrps (long MchCod)
|
|
|
|
|
{
|
|
|
|
|
unsigned NumGrpSel;
|
|
|
|
|
|
|
|
|
|
/***** Create groups associated to the match *****/
|
|
|
|
|
for (NumGrpSel = 0;
|
|
|
|
|
NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps;
|
|
|
|
|
NumGrpSel++)
|
|
|
|
|
/* Create group */
|
|
|
|
|
DB_QueryINSERT ("can not associate a group to a match",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"INSERT INTO mch_groups"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" (MchCod,GrpCod)"
|
|
|
|
|
" VALUES"
|
|
|
|
|
" (%ld,%ld)",
|
|
|
|
|
MchCod,Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel]);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 20:22:32 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************* Remove one group from all matches *********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_RemoveGroup (long GrpCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Remove group from all the matches *****/
|
|
|
|
|
DB_QueryDELETE ("can not remove group"
|
|
|
|
|
" from the associations between matches and groups",
|
|
|
|
|
"DELETE FROM mch_groups WHERE GrpCod=%ld",
|
|
|
|
|
GrpCod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Remove groups of one type from all matches ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_RemoveGroupsOfType (long GrpTypCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Remove group from all the matches *****/
|
|
|
|
|
DB_QueryDELETE ("can not remove groups of a type"
|
|
|
|
|
" from the associations between matches and groups",
|
|
|
|
|
"DELETE FROM mch_groups"
|
|
|
|
|
" USING crs_grp,mch_groups"
|
|
|
|
|
" WHERE crs_grp.GrpTypCod=%ld"
|
|
|
|
|
" AND crs_grp.GrpCod=mch_groups.GrpCod",
|
|
|
|
|
GrpTypCod);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Insert/update a game match being played *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_UpdateMatchStatusInDB (const struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-12 18:24:23 +01:00
|
|
|
|
char *MchSubQuery;
|
2019-09-17 21:01:57 +02:00
|
|
|
|
|
|
|
|
|
/***** Update end time only if match is currently being played *****/
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (Match->Status.Playing) // Match is being played
|
2019-12-12 18:24:23 +01:00
|
|
|
|
{
|
|
|
|
|
if (asprintf (&MchSubQuery,"mch_matches.EndTime=NOW(),") < 0) // Background
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
|
}
|
2019-12-03 15:39:48 +01:00
|
|
|
|
else // Match is paused, not being played
|
2019-12-12 18:24:23 +01:00
|
|
|
|
{
|
|
|
|
|
if (asprintf (&MchSubQuery,"%s","") < 0)
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
|
}
|
2019-09-17 21:01:57 +02:00
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
DB_QueryUPDATE ("can not update match being played",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"UPDATE mch_matches,gam_games"
|
2019-09-17 21:01:57 +02:00
|
|
|
|
" SET %s"
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"mch_matches.QstInd=%u,"
|
|
|
|
|
"mch_matches.QstCod=%ld,"
|
2019-09-25 21:58:12 +02:00
|
|
|
|
"mch_matches.Showing='%s',"
|
2019-12-12 18:24:23 +01:00
|
|
|
|
"mch_matches.Countdown=%ld,"
|
2019-10-22 23:42:22 +02:00
|
|
|
|
"mch_matches.NumCols=%u,"
|
2019-09-25 21:58:12 +02:00
|
|
|
|
"mch_matches.ShowQstResults='%c'"
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" WHERE mch_matches.MchCod=%ld"
|
|
|
|
|
" AND mch_matches.GamCod=gam_games.GamCod"
|
|
|
|
|
" AND gam_games.CrsCod=%ld", // Extra check
|
2019-09-17 21:01:57 +02:00
|
|
|
|
MchSubQuery,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Match->Status.QstInd,Match->Status.QstCod,
|
|
|
|
|
Mch_ShowingStringsDB[Match->Status.Showing],
|
2019-12-12 18:24:23 +01:00
|
|
|
|
Match->Status.Countdown,
|
2019-10-22 23:42:22 +02:00
|
|
|
|
Match->Status.NumCols,
|
2019-09-25 21:58:12 +02:00
|
|
|
|
Match->Status.ShowQstResults ? 'Y' : 'N',
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Match->MchCod,Gbl.Hierarchy.Crs.CrsCod);
|
2019-12-12 18:24:23 +01:00
|
|
|
|
free (MchSubQuery);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (Match->Status.Playing) // Match is being played
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/* Update match as being played */
|
|
|
|
|
Mch_UpdateMatchAsBeingPlayed (Match->MchCod);
|
2019-12-03 15:39:48 +01:00
|
|
|
|
else // Match is paused, not being played
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/* Update match as not being played */
|
|
|
|
|
Mch_SetMatchAsNotBeingPlayed (Match->MchCod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********** Update elapsed time in current question (by a teacher) ***********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_UpdateElapsedTimeInQuestion (const struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Update elapsed time in current question in database *****/
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (Match->Status.Playing && // Match is being played
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Match->Status.Showing != Mch_START &&
|
|
|
|
|
Match->Status.Showing != Mch_END)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
DB_QueryINSERT ("can not update elapsed time in question",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"INSERT INTO mch_times (MchCod,QstInd,ElapsedTime)"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" VALUES (%ld,%u,SEC_TO_TIME(%u))"
|
|
|
|
|
" ON DUPLICATE KEY"
|
|
|
|
|
" UPDATE ElapsedTime=ADDTIME(ElapsedTime,SEC_TO_TIME(%u))",
|
|
|
|
|
Match->MchCod,Match->Status.QstInd,
|
2019-10-01 21:18:53 +02:00
|
|
|
|
Cfg_SECONDS_TO_REFRESH_MATCH_TCH,
|
|
|
|
|
Cfg_SECONDS_TO_REFRESH_MATCH_TCH);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************* Get elapsed time in a match question ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_GetElapsedTimeInQuestion (const struct Match *Match,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
struct Time *Time)
|
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
unsigned NumRows;
|
|
|
|
|
|
|
|
|
|
/***** Query database *****/
|
|
|
|
|
NumRows = (unsigned) DB_QuerySELECT (&mysql_res,"can not get elapsed time",
|
|
|
|
|
"SELECT ElapsedTime"
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" FROM mch_times"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE MchCod=%ld AND QstInd=%u",
|
|
|
|
|
Match->MchCod,Match->Status.QstInd);
|
|
|
|
|
|
|
|
|
|
/***** Get elapsed time from query result *****/
|
|
|
|
|
Mch_GetElapsedTime (NumRows,mysql_res,Time);
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************** Get elapsed time in a match *************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_GetElapsedTimeInMatch (const struct Match *Match,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
struct Time *Time)
|
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
unsigned NumRows;
|
|
|
|
|
|
|
|
|
|
/***** Query database *****/
|
|
|
|
|
NumRows = (unsigned) DB_QuerySELECT (&mysql_res,"can not get elapsed time",
|
|
|
|
|
"SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(ElapsedTime)))"
|
2019-09-17 01:37:07 +02:00
|
|
|
|
" FROM mch_times WHERE MchCod=%ld",
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Match->MchCod);
|
|
|
|
|
|
|
|
|
|
/***** Get elapsed time from query result *****/
|
|
|
|
|
Mch_GetElapsedTime (NumRows,mysql_res,Time);
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************** Get elapsed time in a match *************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_GetElapsedTime (unsigned NumRows,MYSQL_RES *mysql_res,
|
|
|
|
|
struct Time *Time)
|
|
|
|
|
{
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
bool ElapsedTimeGotFromDB = false;
|
|
|
|
|
|
|
|
|
|
/***** Get time from H...H:MM:SS string *****/
|
|
|
|
|
if (NumRows)
|
|
|
|
|
{
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
|
|
|
|
|
if (row[0])
|
|
|
|
|
/* Get the elapsed time (row[0]) */
|
|
|
|
|
if (sscanf (row[0],"%u:%02u:%02u",&Time->Hour,&Time->Minute,&Time->Second) == 3)
|
|
|
|
|
ElapsedTimeGotFromDB = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Initialize time to default value (0) *****/
|
|
|
|
|
if (!ElapsedTimeGotFromDB)
|
|
|
|
|
Time->Hour =
|
|
|
|
|
Time->Minute =
|
|
|
|
|
Time->Second = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-10-18 00:05:21 +02:00
|
|
|
|
/********************** Play/pause match (by a teacher) **********************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-10-18 00:05:21 +02:00
|
|
|
|
void Mch_PlayPauseMatch (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
2019-10-01 21:18:53 +02:00
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
2019-10-17 22:47:44 +02:00
|
|
|
|
/***** Update status *****/
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (Match.Status.Playing) // Match is being played ==> pause it
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Match.Status.Playing = false; // Pause match
|
2019-12-03 15:39:48 +01:00
|
|
|
|
else // Match is paused, not being played ==> play it
|
2019-12-10 21:52:22 +01:00
|
|
|
|
/* If not over, update status */
|
|
|
|
|
if (Match.Status.Showing != Mch_END) // Match not over
|
|
|
|
|
Match.Status.Playing = true; // Start/resume match
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ShowMatchStatusForTch (&Match);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 00:49:03 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******* Change number of columns in answers of a match (by a teacher) *******/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_ChangeNumColsMch (void)
|
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Get number of columns *****/
|
|
|
|
|
Match.Status.NumCols = (unsigned)
|
|
|
|
|
Par_GetParToUnsignedLong ("NumCols",
|
|
|
|
|
1,
|
|
|
|
|
Mch_MAX_COLS,
|
|
|
|
|
Mch_NUM_COLS_DEFAULT);
|
|
|
|
|
|
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-10-23 00:49:03 +02:00
|
|
|
|
Mch_ShowMatchStatusForTch (&Match);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-10-23 00:49:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-14 19:46:26 +02:00
|
|
|
|
/********* Toggle the display of results in a match (by a teacher) ***********/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-25 21:58:12 +02:00
|
|
|
|
void Mch_ToggleVisibilResultsMchQst (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
2019-10-01 21:18:53 +02:00
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Update status *****/
|
2019-09-25 21:58:12 +02:00
|
|
|
|
Match.Status.ShowQstResults = !Match.Status.ShowQstResults; // Toggle display
|
|
|
|
|
if (Match.Status.Showing == Mch_RESULTS &&
|
|
|
|
|
!Match.Status.ShowQstResults)
|
2019-09-14 19:46:26 +02:00
|
|
|
|
Match.Status.Showing = Mch_ANSWERS; // Hide results
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ShowMatchStatusForTch (&Match);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************* Show previous question in a match (by a teacher) **************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
void Mch_BackMatch (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
2019-10-01 21:18:53 +02:00
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Update status *****/
|
|
|
|
|
Mch_SetMatchStatusToPrev (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ShowMatchStatusForTch (&Match);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*************** Show next question in a match (by a teacher) ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
void Mch_ForwardMatch (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
2019-10-01 21:18:53 +02:00
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Update status *****/
|
|
|
|
|
Mch_SetMatchStatusToNext (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ShowMatchStatusForTch (&Match);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************** Set match status to previous (backward) status ***************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_SetMatchStatusToPrev (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** What to show *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
switch (Match->Status.Showing)
|
|
|
|
|
{
|
|
|
|
|
case Mch_START:
|
|
|
|
|
Mch_SetMatchStatusToStart (Match);
|
|
|
|
|
break;
|
|
|
|
|
case Mch_STEM:
|
|
|
|
|
case Mch_END:
|
|
|
|
|
Mch_SetMatchStatusToPrevQst (Match);
|
|
|
|
|
break;
|
|
|
|
|
case Mch_ANSWERS:
|
|
|
|
|
Match->Status.Showing = Mch_STEM;
|
|
|
|
|
break;
|
|
|
|
|
case Mch_RESULTS:
|
|
|
|
|
Match->Status.Showing = Mch_ANSWERS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-12-12 18:24:23 +01:00
|
|
|
|
Match->Status.Countdown = -1L; // No countdown
|
2019-09-17 15:42:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Set match status to previous question ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-17 15:42:41 +02:00
|
|
|
|
static void Mch_SetMatchStatusToPrevQst (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Get index of the previous question *****/
|
|
|
|
|
Match->Status.QstInd = Gam_GetPrevQuestionIndexInGame (Match->GamCod,
|
|
|
|
|
Match->Status.QstInd);
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.QstInd) // Start of questions not reached
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-09-17 15:42:41 +02:00
|
|
|
|
Match->Status.QstCod = Gam_GetQstCodFromQstInd (Match->GamCod,
|
|
|
|
|
Match->Status.QstInd);
|
2019-09-25 21:58:12 +02:00
|
|
|
|
Match->Status.Showing = Match->Status.ShowQstResults ? Mch_RESULTS :
|
|
|
|
|
Mch_ANSWERS;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
2019-12-10 21:52:22 +01:00
|
|
|
|
else // Start of questions reached
|
|
|
|
|
Mch_SetMatchStatusToStart (Match);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************************ Set match status to start **************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-17 15:42:41 +02:00
|
|
|
|
static void Mch_SetMatchStatusToStart (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
Match->Status.QstInd = 0; // Before first question
|
|
|
|
|
Match->Status.QstCod = -1L;
|
|
|
|
|
Match->Status.Playing = false;
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Match->Status.Showing = Mch_START;
|
2019-09-17 15:42:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**************** Set match status to next (forward) status ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_SetMatchStatusToNext (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** What to show *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
switch (Match->Status.Showing)
|
|
|
|
|
{
|
|
|
|
|
case Mch_START:
|
|
|
|
|
Mch_SetMatchStatusToNextQst (Match);
|
|
|
|
|
break;
|
|
|
|
|
case Mch_STEM:
|
|
|
|
|
Match->Status.Showing = Mch_ANSWERS;
|
|
|
|
|
break;
|
|
|
|
|
case Mch_ANSWERS:
|
|
|
|
|
if (Match->Status.ShowQstResults)
|
|
|
|
|
Match->Status.Showing = Mch_RESULTS;
|
|
|
|
|
else
|
2019-09-17 15:42:41 +02:00
|
|
|
|
Mch_SetMatchStatusToNextQst (Match);
|
2019-12-10 21:52:22 +01:00
|
|
|
|
break;
|
|
|
|
|
case Mch_RESULTS:
|
|
|
|
|
Mch_SetMatchStatusToNextQst (Match);
|
|
|
|
|
break;
|
|
|
|
|
case Mch_END:
|
|
|
|
|
Mch_SetMatchStatusToEnd (Match);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-12-12 18:24:23 +01:00
|
|
|
|
Match->Status.Countdown = -1L; // No countdown
|
2019-09-17 15:42:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Set match status to next question ************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-17 15:42:41 +02:00
|
|
|
|
static void Mch_SetMatchStatusToNextQst (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Get index of the next question *****/
|
|
|
|
|
Match->Status.QstInd = Gam_GetNextQuestionIndexInGame (Match->GamCod,
|
|
|
|
|
Match->Status.QstInd);
|
|
|
|
|
|
|
|
|
|
/***** Get question code *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.QstInd < Mch_AFTER_LAST_QUESTION) // End of questions not reached
|
2019-09-17 15:42:41 +02:00
|
|
|
|
{
|
|
|
|
|
Match->Status.QstCod = Gam_GetQstCodFromQstInd (Match->GamCod,
|
|
|
|
|
Match->Status.QstInd);
|
|
|
|
|
Match->Status.Showing = Mch_STEM;
|
2019-09-14 19:46:26 +02:00
|
|
|
|
}
|
2019-12-10 21:52:22 +01:00
|
|
|
|
else // End of questions reached
|
|
|
|
|
Mch_SetMatchStatusToEnd (Match);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************************* Set match status to end ***************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-17 15:42:41 +02:00
|
|
|
|
static void Mch_SetMatchStatusToEnd (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
Match->Status.QstInd = Mch_AFTER_LAST_QUESTION; // After last question
|
|
|
|
|
Match->Status.QstCod = -1L;
|
|
|
|
|
Match->Status.Playing = false;
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Match->Status.Showing = Mch_END;
|
2019-09-17 15:42:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******* Show current match status (number, question, answers, button) *******/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ShowMatchStatusForTch (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Left column *****/
|
|
|
|
|
Mch_ShowLeftColumnTch (Match);
|
|
|
|
|
|
|
|
|
|
/***** Right column *****/
|
2019-09-26 18:19:07 +02:00
|
|
|
|
Mch_ShowRightColumnTch (Match);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************ Show current question being played for a student ***************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-03 02:46:46 +01:00
|
|
|
|
static void Mch_ShowMatchStatusForStd (struct Match *Match,Mch_Update_t Update)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-09-29 19:36:32 +02:00
|
|
|
|
bool ICanPlayThisMatchBasedOnGrps;
|
2019-12-03 02:46:46 +01:00
|
|
|
|
struct Mch_UsrAnswer UsrAnswer;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-29 19:36:32 +02:00
|
|
|
|
/***** Can I play this match? *****/
|
2019-12-05 19:54:28 +01:00
|
|
|
|
ICanPlayThisMatchBasedOnGrps = Mch_CheckIfICanPlayThisMatchBasedOnGrps (Match);
|
2019-09-29 19:36:32 +02:00
|
|
|
|
if (!ICanPlayThisMatchBasedOnGrps)
|
2019-10-26 01:56:36 +02:00
|
|
|
|
Lay_NoPermissionExit ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-03 02:46:46 +01:00
|
|
|
|
/***** Get student's answer to this question
|
|
|
|
|
(<0 ==> no answer) *****/
|
|
|
|
|
Mch_GetQstAnsFromDB (Match->MchCod,
|
|
|
|
|
Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
|
|
|
Match->Status.QstInd,
|
|
|
|
|
&UsrAnswer);
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Left column *****/
|
2019-12-03 02:46:46 +01:00
|
|
|
|
Mch_ShowLeftColumnStd (Match,&UsrAnswer);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Right column *****/
|
2019-12-03 02:46:46 +01:00
|
|
|
|
Mch_ShowRightColumnStd (Match,&UsrAnswer,Update);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-26 01:15:21 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
/********************** Get number of matches in a game **********************/
|
2019-09-26 01:15:21 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-28 02:31:42 +02:00
|
|
|
|
unsigned Mch_GetNumMchsInGame (long GamCod)
|
2019-09-26 01:15:21 +02:00
|
|
|
|
{
|
2019-09-26 21:27:36 +02:00
|
|
|
|
/***** Trivial check *****/
|
|
|
|
|
if (GamCod < 0) // A non-existing game...
|
|
|
|
|
return 0; // ...has no matches
|
|
|
|
|
|
2019-09-26 01:15:21 +02:00
|
|
|
|
/***** Get number of matches in a game from database *****/
|
|
|
|
|
return
|
|
|
|
|
(unsigned) DB_QueryCOUNT ("can not get number of matches of a game",
|
|
|
|
|
"SELECT COUNT(*) FROM mch_matches"
|
|
|
|
|
" WHERE GamCod=%ld",
|
|
|
|
|
GamCod);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 21:52:22 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*************** Get number of unfinished matches in a game ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
unsigned Mch_GetNumUnfinishedMchsInGame (long GamCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Trivial check *****/
|
|
|
|
|
if (GamCod < 0) // A non-existing game...
|
|
|
|
|
return 0; // ...has no matches
|
|
|
|
|
|
|
|
|
|
/***** Get number of matches in a game from database *****/
|
|
|
|
|
return
|
|
|
|
|
(unsigned) DB_QueryCOUNT ("can not get number of unfinished matches of a game",
|
|
|
|
|
"SELECT COUNT(*) FROM mch_matches"
|
|
|
|
|
" WHERE GamCod=%ld AND Showing<>'%s'",
|
|
|
|
|
GamCod,Mch_ShowingStringsDB[Mch_END]);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************ Check if I belong to any of the groups of a match **************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
bool Mch_CheckIfICanPlayThisMatchBasedOnGrps (const struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-09-29 19:36:32 +02:00
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_STD:
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/***** Check if I belong to any of the groups
|
|
|
|
|
associated to the match *****/
|
|
|
|
|
return (DB_QueryCOUNT ("can not check if I can play a match",
|
|
|
|
|
"SELECT COUNT(*) FROM mch_matches"
|
|
|
|
|
" WHERE MchCod=%ld"
|
|
|
|
|
" AND"
|
|
|
|
|
"(MchCod NOT IN"
|
|
|
|
|
" (SELECT MchCod FROM mch_groups)"
|
|
|
|
|
" OR"
|
|
|
|
|
" MchCod IN"
|
|
|
|
|
" (SELECT mch_groups.MchCod"
|
|
|
|
|
" FROM mch_groups,crs_grp_usr"
|
|
|
|
|
" WHERE crs_grp_usr.UsrCod=%ld"
|
|
|
|
|
" AND mch_groups.GrpCod=crs_grp_usr.GrpCod))",
|
|
|
|
|
Match->MchCod,Gbl.Usrs.Me.UsrDat.UsrCod) != 0);
|
2019-09-29 19:36:32 +02:00
|
|
|
|
break;
|
|
|
|
|
case Rol_NET:
|
2019-12-05 19:54:28 +01:00
|
|
|
|
/***** Only if I am the creator *****/
|
|
|
|
|
return (Match->UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod);
|
2019-09-29 19:36:32 +02:00
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_SYS_ADM:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-09-26 18:19:07 +02:00
|
|
|
|
/*********** Show left column when playing a match (as a teacher) ************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ShowLeftColumnTch (struct Match *Match)
|
2019-09-26 19:54:09 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Start left container *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_LEFT\"");
|
2019-09-30 16:25:44 +02:00
|
|
|
|
|
|
|
|
|
/***** Refreshable part *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match_left\" class=\"MCH_REFRESHABLE_TEACHER\"");
|
2019-09-30 16:25:44 +02:00
|
|
|
|
Mch_ShowRefreshablePartTch (Match);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-26 19:54:09 +02:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Put forms to start countdown *****/
|
|
|
|
|
Mch_PutFormsCountdown (Match);
|
|
|
|
|
|
2019-09-30 16:25:44 +02:00
|
|
|
|
/***** Buttons *****/
|
|
|
|
|
Mch_PutMatchControlButtons (Match);
|
|
|
|
|
|
2019-10-22 20:43:03 +02:00
|
|
|
|
/***** Put forms to choice which projects to show *****/
|
|
|
|
|
Set_StartSettingsHead ();
|
2019-10-22 22:39:37 +02:00
|
|
|
|
Mch_ShowFormColumns (Match);
|
2019-10-22 20:43:03 +02:00
|
|
|
|
Set_EndSettingsHead ();
|
|
|
|
|
|
2019-09-30 16:25:44 +02:00
|
|
|
|
/***** Write button to request viewing results *****/
|
2019-10-31 08:47:16 +01:00
|
|
|
|
Mch_PutCheckboxResult (Match);
|
2019-09-26 19:54:09 +02:00
|
|
|
|
|
|
|
|
|
/***** End left container *****/
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-26 19:54:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Show left refreshable part for teachers *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-30 16:25:44 +02:00
|
|
|
|
static void Mch_ShowRefreshablePartTch (struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-12 09:14:26 +01:00
|
|
|
|
/***** Write elapsed time in match *****/
|
|
|
|
|
Mch_WriteElapsedTimeInMch (Match);
|
|
|
|
|
|
|
|
|
|
/***** Write number of question *****/
|
|
|
|
|
Mch_ShowNumQstInMch (Match);
|
|
|
|
|
|
|
|
|
|
/***** Write elapsed time in question *****/
|
|
|
|
|
Mch_WriteElapsedTimeInQst (Match);
|
|
|
|
|
|
|
|
|
|
/***** Number of users who have responded this question *****/
|
|
|
|
|
Mch_WriteNumRespondersQst (Match);
|
2019-12-14 01:31:32 +01:00
|
|
|
|
|
|
|
|
|
/***** Write hourglass *****/
|
|
|
|
|
Mch_PutCountdownAndHourglassIcon (Match);
|
2019-12-12 09:14:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Write elapsed time in current match ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
static void Mch_WriteElapsedTimeInMch (struct Match *Match)
|
|
|
|
|
{
|
2019-09-14 12:59:34 +02:00
|
|
|
|
struct Time Time;
|
|
|
|
|
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_TOP\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
/***** Get elapsed time in match *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_GetElapsedTimeInMatch (Match,&Time);
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
|
|
|
|
/***** Write elapsed time in hh:mm'ss" format *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Dat_WriteHoursMinutesSeconds (&Time);
|
|
|
|
|
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-12-12 09:14:26 +01:00
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Write elapsed time in current question *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
static void Mch_WriteElapsedTimeInQst (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
struct Time Time;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_TIME_QST\"");
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
|
|
|
|
switch (Match->Status.Showing)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-12 09:14:26 +01:00
|
|
|
|
case Mch_START:
|
|
|
|
|
case Mch_END:
|
|
|
|
|
HTM_Hyphen (); // Do not write elapsed time
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Mch_GetElapsedTimeInQuestion (Match,&Time);
|
|
|
|
|
Dat_WriteHoursMinutesSeconds (&Time);
|
|
|
|
|
break;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-12-12 09:14:26 +01:00
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*************** Write number of responders to a match question **************/
|
|
|
|
|
/*****************************************************************************/
|
2019-12-12 18:24:23 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
static void Mch_WriteNumRespondersQst (struct Match *Match)
|
2019-12-13 23:38:29 +01:00
|
|
|
|
{
|
2019-12-14 01:31:32 +01:00
|
|
|
|
extern const char *Txt_MATCH_respond;
|
2019-12-13 23:38:29 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Begin block *****/
|
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_NUM_ANSWERERS\"");
|
|
|
|
|
HTM_Txt (Txt_MATCH_respond);
|
|
|
|
|
HTM_BR ();
|
|
|
|
|
HTM_STRONG_Begin ();
|
2019-12-13 23:38:29 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Write number of responders *****/
|
|
|
|
|
switch (Match->Status.Showing)
|
2019-12-13 23:38:29 +01:00
|
|
|
|
{
|
2019-12-14 01:31:32 +01:00
|
|
|
|
case Mch_START:
|
|
|
|
|
case Mch_END:
|
|
|
|
|
HTM_Hyphen (); // Do not write number of responders
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
HTM_Unsigned (Mch_GetNumUsrsWhoAnsweredQst (Match->MchCod,
|
|
|
|
|
Match->Status.QstInd));
|
|
|
|
|
break;
|
2019-12-13 23:38:29 +01:00
|
|
|
|
}
|
2019-12-12 18:24:23 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Write number of players *****/
|
|
|
|
|
if (Match->Status.Playing) // Match is being played
|
2019-12-13 00:36:01 +01:00
|
|
|
|
{
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/* Get current number of players */
|
|
|
|
|
Mch_GetNumPlayers (Match);
|
2019-12-12 18:24:23 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/* Show current number of players */
|
|
|
|
|
HTM_TxtF ("/%u",Match->Status.NumPlayers);
|
2019-12-13 00:36:01 +01:00
|
|
|
|
}
|
2019-12-12 18:24:23 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** End block *****/
|
|
|
|
|
HTM_STRONG_End ();
|
2019-12-12 18:24:23 +01:00
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*************** Write current countdown and hourglass icon ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-13 01:21:09 +01:00
|
|
|
|
static void Mch_PutCountdownAndHourglassIcon (struct Match *Match)
|
2019-12-13 01:04:09 +01:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Countdown;
|
|
|
|
|
const char *Class;
|
|
|
|
|
const char *Icon;
|
|
|
|
|
|
|
|
|
|
/***** Set hourglass icon depending on countdown *****/
|
|
|
|
|
if (Match->Status.Showing == Mch_END) // Match over
|
|
|
|
|
{
|
|
|
|
|
Class = "BT_LINK_OFF MCH_BUTTON_HIDDEN MCH_GREEN";
|
|
|
|
|
Icon = "fa-hourglass-start";
|
|
|
|
|
}
|
|
|
|
|
else if (Match->Status.Countdown < 0) // No countdown
|
|
|
|
|
{
|
|
|
|
|
Class = "BT_LINK_OFF MCH_BUTTON_OFF MCH_GREEN";
|
|
|
|
|
Icon = "fa-hourglass-start";
|
|
|
|
|
}
|
|
|
|
|
else if (Match->Status.Countdown > Mch_COUNTDOWN_SECONDS_MEDIUM) // Countdown in progress
|
|
|
|
|
{
|
|
|
|
|
Class = "BT_LINK_OFF MCH_BUTTON_OFF MCH_LIMEGREEN";
|
|
|
|
|
Icon = "fa-hourglass-start";
|
|
|
|
|
}
|
|
|
|
|
else if (Match->Status.Countdown > Mch_COUNTDOWN_SECONDS_SMALL) // Countdown in progress
|
|
|
|
|
{
|
|
|
|
|
Class = "BT_LINK_OFF MCH_BUTTON_OFF MCH_YELLOW";
|
|
|
|
|
Icon = "fa-hourglass-half";
|
|
|
|
|
}
|
|
|
|
|
else // Countdown about to end
|
|
|
|
|
{
|
|
|
|
|
Class = "BT_LINK_OFF MCH_BUTTON_OFF MCH_RED";
|
|
|
|
|
Icon = "fa-hourglass-end";
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-13 01:21:09 +01:00
|
|
|
|
/***** Write countdown and put hourglass icon *****/
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_SHOW_HOURGLASS\"");
|
2019-12-13 01:04:09 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BIGBUTTON_CONT\"");
|
|
|
|
|
HTM_BUTTON_BUTTON_Begin (Txt_Countdown,Class,NULL);
|
2019-12-13 01:21:09 +01:00
|
|
|
|
|
|
|
|
|
/* Countdown */
|
2019-12-13 01:04:09 +01:00
|
|
|
|
if (Match->Status.Countdown > 0)
|
|
|
|
|
HTM_TxtF (" %02ld″",Match->Status.Countdown);
|
|
|
|
|
else
|
|
|
|
|
HTM_NBSP ();
|
2019-12-13 01:21:09 +01:00
|
|
|
|
HTM_BR ();
|
|
|
|
|
|
|
|
|
|
/* Icon */
|
|
|
|
|
HTM_TxtF ("<i class=\"fas %s\"></i>",Icon);
|
|
|
|
|
|
2019-12-13 01:04:09 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
|
|
|
|
HTM_DIV_End ();
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_DIV_End ();
|
2019-12-13 01:04:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/******************** Put all forms to start countdowns **********************/
|
2019-12-13 01:04:09 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
static void Mch_PutFormsCountdown (struct Match *Match)
|
2019-12-12 09:14:26 +01:00
|
|
|
|
{
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Start container *****/
|
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_SHOW_HOURGLASS\"");
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Put forms to start countdown *****/
|
|
|
|
|
Mch_PutFormCountdown (Match,-1 ,"MCH_GREEN" );
|
|
|
|
|
Mch_PutFormCountdown (Match,Mch_COUNTDOWN_SECONDS_LARGE ,"MCH_LIMEGREEN");
|
|
|
|
|
Mch_PutFormCountdown (Match,Mch_COUNTDOWN_SECONDS_MEDIUM,"MCH_YELLOW" );
|
|
|
|
|
Mch_PutFormCountdown (Match,Mch_COUNTDOWN_SECONDS_SMALL ,"MCH_RED" );
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** End container *****/
|
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****** Put a form to start a countdown with a given number of seconds *******/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_PutFormCountdown (struct Match *Match,long Seconds,const char *Color)
|
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Countdown;
|
|
|
|
|
char *OnSubmit;
|
|
|
|
|
bool PutForm = Match->Status.Showing != Mch_END;
|
|
|
|
|
|
|
|
|
|
if (PutForm)
|
2019-12-12 09:14:26 +01:00
|
|
|
|
{
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Start form *****/
|
|
|
|
|
if (asprintf (&OnSubmit,"updateMatchTch('match_left',"
|
|
|
|
|
"'act=%ld&ses=%s&MchCod=%ld&Countdown=%ld');"
|
|
|
|
|
" return false;", // return false is necessary to not submit form
|
|
|
|
|
Act_GetActCod (ActMchCntDwn),Gbl.Session.Id,
|
|
|
|
|
Match->MchCod,Seconds) < 0)
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
|
Frm_StartFormOnSubmit (ActUnk,OnSubmit);
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
2019-10-18 00:05:21 +02:00
|
|
|
|
{
|
2019-12-14 01:31:32 +01:00
|
|
|
|
}
|
2019-09-30 14:55:55 +02:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/***** Put icon *****/
|
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_SMALLBUTTON_CONT\"");
|
|
|
|
|
|
2019-12-30 21:47:07 +01:00
|
|
|
|
HTM_BUTTON_SUBMIT_Begin (PutForm ? Txt_Countdown :
|
|
|
|
|
NULL,
|
|
|
|
|
Str_BuildStringStr (PutForm ? "BT_LINK MCH_BUTTON_ON %s" :
|
|
|
|
|
"BT_LINK_OFF MCH_BUTTON_HIDDEN %s",
|
|
|
|
|
Color),
|
|
|
|
|
NULL);
|
|
|
|
|
Str_FreeString ();
|
2019-12-14 01:31:32 +01:00
|
|
|
|
|
|
|
|
|
HTM_NBSP ();
|
|
|
|
|
if (Seconds >= 0)
|
|
|
|
|
HTM_TxtF ("%ld″",Seconds);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
HTM_Txt ("∞");
|
|
|
|
|
HTM_NBSP ();
|
2019-10-18 00:05:21 +02:00
|
|
|
|
}
|
2019-12-12 09:14:26 +01:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
|
|
|
|
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-12-14 01:31:32 +01:00
|
|
|
|
|
|
|
|
|
/***** End form *****/
|
|
|
|
|
if (PutForm)
|
|
|
|
|
{
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
free (OnSubmit);
|
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-09-26 18:19:07 +02:00
|
|
|
|
/********** Show right column when playing a match (as a teacher) ************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowRightColumnTch (const struct Match *Match)
|
2019-09-26 18:19:07 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Start right container *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_RIGHT\"");
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
|
|
|
|
/***** Top row: match title *****/
|
|
|
|
|
Mch_ShowMatchTitle (Match);
|
|
|
|
|
|
|
|
|
|
/***** Bottom row: current question and possible answers *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.Showing == Mch_END) // Match over
|
2019-10-21 13:36:28 +02:00
|
|
|
|
Mch_ShowMatchScore (Match);
|
2019-12-10 21:52:22 +01:00
|
|
|
|
else // Match not over
|
|
|
|
|
Mch_ShowQuestionAndAnswersTch (Match);
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
|
|
|
|
/***** End right container *****/
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-26 18:19:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********** Show left column when playing a match (as a student) ************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowLeftColumnStd (const struct Match *Match,
|
2019-12-03 02:46:46 +01:00
|
|
|
|
const struct Mch_UsrAnswer *UsrAnswer)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-03 02:46:46 +01:00
|
|
|
|
bool Answered = UsrAnswer->NumOpt >= 0;
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Start left container *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_LEFT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Top *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_TOP\"");
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Write number of question *****/
|
2019-12-12 09:14:26 +01:00
|
|
|
|
Mch_ShowNumQstInMch (Match);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
switch (Match->Status.Showing)
|
2019-12-04 01:19:31 +01:00
|
|
|
|
{
|
2019-12-12 09:14:26 +01:00
|
|
|
|
case Mch_START:
|
|
|
|
|
case Mch_END:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/***** Write whether question is answered or not *****/
|
|
|
|
|
Mch_PutIfAnswered (Match,Answered);
|
|
|
|
|
|
|
|
|
|
if (Match->Status.Playing && // Match is being played
|
|
|
|
|
Match->Status.Showing == Mch_ANSWERS && // Teacher's screen is showing question answers
|
|
|
|
|
Answered) // I have answered this question
|
|
|
|
|
/***** Put icon to remove my answet *****/
|
|
|
|
|
Mch_PutIconToRemoveMyAnswer (Match);
|
|
|
|
|
break;
|
2019-12-04 01:19:31 +01:00
|
|
|
|
}
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** End left container *****/
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-26 18:19:07 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********** Show right column when playing a match (as a student) ************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-03 02:46:46 +01:00
|
|
|
|
static void Mch_ShowRightColumnStd (struct Match *Match,
|
|
|
|
|
const struct Mch_UsrAnswer *UsrAnswer,
|
|
|
|
|
Mch_Update_t Update)
|
2019-09-26 18:19:07 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Please_wait_;
|
|
|
|
|
|
|
|
|
|
/***** Start right container *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_RIGHT\"");
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
|
|
|
|
/***** Top row *****/
|
|
|
|
|
Mch_ShowMatchTitle (Match);
|
|
|
|
|
|
|
|
|
|
/***** Bottom row *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.Playing) // Match is being played
|
2019-09-26 18:19:07 +02:00
|
|
|
|
{
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.Showing == Mch_END) // Match over
|
|
|
|
|
Mch_ShowWaitImage (Txt_Please_wait_);
|
|
|
|
|
else // Match not over
|
2019-09-29 21:33:27 +02:00
|
|
|
|
{
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BOTTOM\"");
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
/***** Update players ******/
|
2019-12-02 09:57:17 +01:00
|
|
|
|
if (Mch_RegisterMeAsPlayerInMatch (Match))
|
2019-12-04 01:19:31 +01:00
|
|
|
|
{
|
|
|
|
|
if (Match->Status.Showing == Mch_ANSWERS) // Teacher's screen is showing question answers
|
|
|
|
|
/* Show current question and possible answers */
|
2019-12-04 22:22:42 +01:00
|
|
|
|
if (!Mch_ShowQuestionAndAnswersStd (Match,UsrAnswer,Update))
|
|
|
|
|
Ale_ShowAlert (Ale_ERROR,"Wrong question.");
|
2019-12-04 01:19:31 +01:00
|
|
|
|
}
|
2019-12-02 09:57:17 +01:00
|
|
|
|
else
|
|
|
|
|
Ale_ShowAlert (Ale_ERROR,"You can not join this match.");
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-29 21:33:27 +02:00
|
|
|
|
}
|
2019-09-26 18:19:07 +02:00
|
|
|
|
}
|
2019-12-10 21:52:22 +01:00
|
|
|
|
else // Match is not being played
|
2019-09-29 21:33:27 +02:00
|
|
|
|
Mch_ShowWaitImage (Txt_Please_wait_);
|
2019-09-26 18:19:07 +02:00
|
|
|
|
|
|
|
|
|
/***** End right container *****/
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-26 18:19:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 19:46:26 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************* Show number of question in game ***********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
static void Mch_ShowNumQstInMch (const struct Match *Match)
|
2019-09-14 19:46:26 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_MATCH_Start;
|
|
|
|
|
extern const char *Txt_MATCH_End;
|
|
|
|
|
unsigned NumQsts = Gam_GetNumQstsGame (Match->GamCod);
|
|
|
|
|
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_NUM_QST\"");
|
2019-12-10 21:52:22 +01:00
|
|
|
|
switch (Match->Status.Showing)
|
|
|
|
|
{
|
|
|
|
|
case Mch_START: // Not started
|
|
|
|
|
HTM_Txt (Txt_MATCH_Start);
|
|
|
|
|
break;
|
|
|
|
|
case Mch_END: // Match over
|
|
|
|
|
HTM_Txt (Txt_MATCH_End);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
HTM_TxtF ("%u/%u",Match->Status.QstInd,NumQsts);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 19:46:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Put buttons to control a match ***********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_PutMatchControlButtons (const struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Go_back;
|
|
|
|
|
extern const char *Txt_Go_forward;
|
|
|
|
|
extern const char *Txt_Pause;
|
|
|
|
|
extern const char *Txt_Start;
|
|
|
|
|
extern const char *Txt_Resume;
|
|
|
|
|
|
|
|
|
|
/***** Start buttons container *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BUTTONS_CONT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Left button *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BUTTON_LEFT_CONT\"");
|
2019-12-12 09:14:26 +01:00
|
|
|
|
switch (Match->Status.Showing)
|
|
|
|
|
{
|
|
|
|
|
case Mch_START:
|
|
|
|
|
/* Put button to close browser tab */
|
|
|
|
|
Mch_PutBigButtonClose ();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Put button to go back */
|
|
|
|
|
Mch_PutBigButton (ActBckMch,"backward",Match->MchCod,
|
|
|
|
|
Mch_ICON_PREVIOUS,Txt_Go_back);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Center button *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BUTTON_CENTER_CONT\"");
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (Match->Status.Playing) // Match is being played
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/* Put button to pause match */
|
2019-10-17 22:47:44 +02:00
|
|
|
|
Mch_PutBigButton (ActPlyPauMch,"play_pause",Match->MchCod,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ICON_PAUSE,Txt_Pause);
|
2019-12-03 15:39:48 +01:00
|
|
|
|
else // Match is paused, not being played
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-10 21:52:22 +01:00
|
|
|
|
switch (Match->Status.Showing)
|
|
|
|
|
{
|
|
|
|
|
case Mch_START: // Match just started, before first question
|
|
|
|
|
/* Put button to start playing match */
|
|
|
|
|
Mch_PutBigButton (ActPlyPauMch,"play_pause",Match->MchCod,
|
|
|
|
|
Mch_ICON_PLAY,Txt_Start);
|
|
|
|
|
break;
|
|
|
|
|
case Mch_END: // Match over
|
|
|
|
|
/* Put disabled button to play match */
|
2019-12-13 00:36:01 +01:00
|
|
|
|
Mch_PutBigButtonHidden (Mch_ICON_PLAY);
|
2019-12-10 21:52:22 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Put button to resume match */
|
|
|
|
|
Mch_PutBigButton (ActPlyPauMch,"play_pause",Match->MchCod,
|
|
|
|
|
Mch_ICON_PLAY,Txt_Resume);
|
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Right button *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BUTTON_RIGHT_CONT\"");
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.Showing == Mch_END) // Match over
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/* Put button to close browser tab */
|
|
|
|
|
Mch_PutBigButtonClose ();
|
2019-12-10 21:52:22 +01:00
|
|
|
|
else // Match not over
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/* Put button to show answers */
|
2019-10-17 22:47:44 +02:00
|
|
|
|
Mch_PutBigButton (ActFwdMch,"forward",Match->MchCod,
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ICON_NEXT,Txt_Go_forward);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** End buttons container *****/
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-10-22 22:39:37 +02:00
|
|
|
|
/** Show form to choice whether to show answers in one column or two columns */
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowFormColumns (const struct Match *Match)
|
2019-10-22 22:39:37 +02:00
|
|
|
|
{
|
2019-10-22 23:42:22 +02:00
|
|
|
|
extern const char *Txt_column;
|
2019-10-22 22:39:37 +02:00
|
|
|
|
extern const char *Txt_columns;
|
|
|
|
|
unsigned NumCols;
|
2019-10-22 23:42:22 +02:00
|
|
|
|
static const char *NumColsIcon[1 + Mch_MAX_COLS] =
|
2019-10-22 22:39:37 +02:00
|
|
|
|
{
|
2019-10-23 02:18:24 +02:00
|
|
|
|
"", // Not used
|
|
|
|
|
"1col.png", // 1 column
|
|
|
|
|
"2col.png", // 2 columns
|
|
|
|
|
"3col.png", // 3 columns
|
|
|
|
|
"4col.png", // 4 columns
|
2019-10-22 22:39:37 +02:00
|
|
|
|
};
|
|
|
|
|
|
2019-10-22 23:42:22 +02:00
|
|
|
|
/***** Begin selector *****/
|
2019-10-22 22:39:37 +02:00
|
|
|
|
Set_StartOneSettingSelector ();
|
2019-10-22 23:42:22 +02:00
|
|
|
|
|
|
|
|
|
for (NumCols = 1;
|
|
|
|
|
NumCols <= Mch_MAX_COLS;
|
2019-10-22 22:39:37 +02:00
|
|
|
|
NumCols++)
|
|
|
|
|
{
|
2019-12-30 20:41:40 +01:00
|
|
|
|
/* Begin container for this option */
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"%s\"",
|
|
|
|
|
(Match->Status.NumCols == NumCols) ? "PREF_ON" :
|
|
|
|
|
"PREF_OFF");
|
|
|
|
|
|
2019-12-30 20:41:40 +01:00
|
|
|
|
/* Begin form */
|
2019-10-23 00:49:03 +02:00
|
|
|
|
Frm_StartForm (ActChgNumColMch);
|
2019-10-22 22:39:37 +02:00
|
|
|
|
Mch_PutParamMchCod (Match->MchCod); // Current match being played
|
2019-10-23 00:49:03 +02:00
|
|
|
|
Mch_PutParamNumCols (NumCols); // Number of columns
|
2019-10-22 22:39:37 +02:00
|
|
|
|
|
2019-12-30 20:41:40 +01:00
|
|
|
|
/* Number of columns */
|
|
|
|
|
Ico_PutSettingIconLink (NumColsIcon[NumCols],
|
2019-12-30 21:47:07 +01:00
|
|
|
|
Str_BuildStringLongStr ((long) NumCols,
|
|
|
|
|
NumCols == 1 ? Txt_column :
|
|
|
|
|
Txt_columns));
|
|
|
|
|
Str_FreeString ();
|
2019-10-22 23:42:22 +02:00
|
|
|
|
|
2019-12-30 20:41:40 +01:00
|
|
|
|
/* End form */
|
2019-10-22 22:39:37 +02:00
|
|
|
|
Frm_EndForm ();
|
2019-10-22 23:42:22 +02:00
|
|
|
|
|
2019-12-30 20:41:40 +01:00
|
|
|
|
/* End container for this option */
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-10-22 22:39:37 +02:00
|
|
|
|
}
|
2019-10-22 23:42:22 +02:00
|
|
|
|
|
|
|
|
|
/***** End selector *****/
|
2019-10-22 22:39:37 +02:00
|
|
|
|
Set_EndOneSettingSelector ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-10-23 00:49:03 +02:00
|
|
|
|
/******** Write parameter with number of columns in answers of match *********/
|
2019-10-22 22:39:37 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-14 19:46:26 +02:00
|
|
|
|
|
2019-10-23 00:49:03 +02:00
|
|
|
|
static void Mch_PutParamNumCols (unsigned NumCols) // Number of columns
|
|
|
|
|
{
|
2019-11-03 13:19:32 +01:00
|
|
|
|
Par_PutHiddenParamUnsigned (NULL,"NumCols",NumCols);
|
2019-10-23 00:49:03 +02:00
|
|
|
|
}
|
2019-09-14 19:46:26 +02:00
|
|
|
|
|
2019-10-31 08:47:16 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Put checkbox to select if show results ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_PutCheckboxResult (const struct Match *Match)
|
2019-10-31 08:47:16 +01:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_View_results;
|
|
|
|
|
|
2019-12-12 18:24:23 +01:00
|
|
|
|
/***** Begin container *****/
|
2019-11-04 22:42:03 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_SHOW_RESULTS\"");
|
2019-10-31 08:47:16 +01:00
|
|
|
|
|
2019-12-12 18:24:23 +01:00
|
|
|
|
/***** Begin form *****/
|
2019-10-31 08:47:16 +01:00
|
|
|
|
Frm_StartForm (ActChgVisResMchQst);
|
|
|
|
|
Mch_PutParamMchCod (Match->MchCod); // Current match being played
|
|
|
|
|
|
|
|
|
|
/***** Put icon with link *****/
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_BUTTON_SUBMIT_Begin (Txt_View_results,"BT_LINK DAT ICO_HIGHLIGHT",NULL);
|
2019-11-11 00:15:44 +01:00
|
|
|
|
HTM_TxtF ("<i class=\"%s\"></i>",
|
|
|
|
|
Match->Status.ShowQstResults ? "fas fa-toggle-on" :
|
|
|
|
|
"fas fa-toggle-off");
|
2019-11-11 10:59:24 +01:00
|
|
|
|
HTM_TxtF (" %s",Txt_View_results);
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
2019-10-31 08:47:16 +01:00
|
|
|
|
|
|
|
|
|
/***** End form *****/
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
|
|
|
|
|
/***** End container *****/
|
2019-11-04 22:42:03 +01:00
|
|
|
|
HTM_DIV_End ();
|
2019-10-31 08:47:16 +01:00
|
|
|
|
}
|
2019-10-22 20:43:03 +02:00
|
|
|
|
|
2019-12-03 02:46:46 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Put checkbox to select if show results ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_PutIfAnswered (const struct Match *Match,bool Answered)
|
|
|
|
|
{
|
2019-12-03 19:36:30 +01:00
|
|
|
|
extern const char *Txt_View_my_answer;
|
2019-12-04 01:19:31 +01:00
|
|
|
|
extern const char *Txt_MATCH_QUESTION_Answered;
|
|
|
|
|
extern const char *Txt_MATCH_QUESTION_Unanswered;
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
|
|
|
|
/***** Start container *****/
|
2019-12-12 18:24:23 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_SHOW_ANSWERED\"");
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
|
|
|
|
/***** Put icon with link *****/
|
2019-12-04 01:19:31 +01:00
|
|
|
|
if (Match->Status.Playing && // Match is being played
|
|
|
|
|
Match->Status.Showing == Mch_ANSWERS && // Teacher's screen is showing question answers
|
|
|
|
|
Answered) // I have answered this question
|
2019-12-03 02:46:46 +01:00
|
|
|
|
{
|
|
|
|
|
/* Start form */
|
|
|
|
|
Frm_StartForm (ActSeeMchAnsQstStd);
|
|
|
|
|
Mch_PutParamMchCod (Match->MchCod); // Current match being played
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_BUTTON_OnMouseDown_Begin (Txt_View_my_answer,"BT_LINK DAT_SMALL_GREEN");
|
2019-12-03 19:36:30 +01:00
|
|
|
|
HTM_TxtF ("<i class=\"%s\"></i>","fas fa-check-circle");
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_TxtF (" %s",Txt_MATCH_QUESTION_Answered);
|
2019-12-03 19:36:30 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
|
|
|
|
/* End form */
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"%s\"",Answered ? "DAT_SMALL_GREEN" :
|
|
|
|
|
"DAT_SMALL_RED");
|
2019-12-03 02:46:46 +01:00
|
|
|
|
HTM_TxtF ("<i class=\"%s\" title=\"%s\"></i>",
|
|
|
|
|
Answered ? "fas fa-check-circle" :
|
|
|
|
|
"fas fa-exclamation-circle",
|
2019-12-04 01:19:31 +01:00
|
|
|
|
Answered ? Txt_MATCH_QUESTION_Answered :
|
|
|
|
|
Txt_MATCH_QUESTION_Unanswered);
|
|
|
|
|
HTM_TxtF (" %s",Answered ? Txt_MATCH_QUESTION_Answered :
|
|
|
|
|
Txt_MATCH_QUESTION_Unanswered);
|
2019-12-03 02:46:46 +01:00
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** End container *****/
|
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Put checkbox to select if show results ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_PutIconToRemoveMyAnswer (const struct Match *Match)
|
2019-12-03 02:46:46 +01:00
|
|
|
|
{
|
2019-12-04 01:19:31 +01:00
|
|
|
|
extern const char *Txt_Delete_my_answer;
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
|
|
|
|
/***** Start container *****/
|
2019-12-12 18:24:23 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_REM_MY_ANS\"");
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
|
|
|
|
/***** Start form *****/
|
|
|
|
|
Frm_StartForm (ActRemMchAnsQstStd);
|
|
|
|
|
Mch_PutParamMchCod (Match->MchCod); // Current match being played
|
|
|
|
|
Gam_PutParamQstInd (Match->Status.QstInd); // Current question index shown
|
|
|
|
|
|
|
|
|
|
/***** Put icon with link *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BIGBUTTON_CONT\"");
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_BUTTON_OnMouseDown_Begin (Txt_Delete_my_answer,"BT_LINK MCH_BUTTON_ON ICO_DARKRED");
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_Txt ("<i class=\"fas fa-trash\"></i>");
|
|
|
|
|
HTM_BUTTON_End ();
|
2019-12-03 02:46:46 +01:00
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
|
|
|
|
|
/***** End form *****/
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
|
|
|
|
|
/***** End container *****/
|
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************************** Show match title ******************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowMatchTitle (const struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Match title *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_TOP\"");
|
2019-11-10 12:36:37 +01:00
|
|
|
|
HTM_Txt (Match->Title);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***** Show question and its answers when playing a match (as a teacher) *****/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_MATCH_Paused;
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
/***** Trivial check: do not show anything on match start and end *****/
|
|
|
|
|
switch (Match->Status.Showing)
|
|
|
|
|
{
|
|
|
|
|
case Mch_START:
|
|
|
|
|
case Mch_END:
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Get data of question from database *****/
|
|
|
|
|
if (!DB_QuerySELECT (&mysql_res,"can not get data of a question",
|
|
|
|
|
"SELECT AnsType," // row[0]
|
|
|
|
|
"Stem," // row[1]
|
|
|
|
|
"MedCod" // row[2]
|
|
|
|
|
" FROM tst_questions"
|
|
|
|
|
" WHERE QstCod=%ld",
|
|
|
|
|
Match->Status.QstCod))
|
|
|
|
|
Ale_ShowAlert (Ale_ERROR,"Question doesn't exist.");
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
|
|
|
|
|
/***** Show question *****/
|
|
|
|
|
/* Get answer type (row[0]) */
|
|
|
|
|
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]);
|
2019-09-23 21:39:54 +02:00
|
|
|
|
if (Gbl.Test.AnswerType != Tst_ANS_UNIQUE_CHOICE)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong answer type.");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BOTTOM\""); // Bottom
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/* Write stem (row[1]) */
|
2019-10-21 21:36:31 +02:00
|
|
|
|
Tst_WriteQstStem (row[1],"MCH_TCH_STEM");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/* Get media (row[2]) */
|
|
|
|
|
Gbl.Test.Media.MedCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
|
|
|
Med_GetMediaDataByCod (&Gbl.Test.Media);
|
|
|
|
|
|
|
|
|
|
/* Show media */
|
|
|
|
|
Med_ShowMedia (&Gbl.Test.Media,
|
|
|
|
|
"TEST_MED_EDIT_LIST_STEM_CONTAINER",
|
|
|
|
|
"TEST_MED_EDIT_LIST_STEM");
|
|
|
|
|
|
2019-09-24 01:41:51 +02:00
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
|
|
|
|
|
/***** Write answers? *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
switch (Match->Status.Showing)
|
|
|
|
|
{
|
|
|
|
|
case Mch_ANSWERS:
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (Match->Status.Playing) // Match is being played
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/* Write answers */
|
2019-10-23 01:30:11 +02:00
|
|
|
|
Mch_WriteAnswersMatchResult (Match,
|
2019-10-21 21:36:31 +02:00
|
|
|
|
"MCH_TCH_ANS",
|
2019-09-16 00:15:40 +02:00
|
|
|
|
false); // Don't show result
|
2019-12-03 15:39:48 +01:00
|
|
|
|
else // Match is paused, not being played
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_ShowWaitImage (Txt_MATCH_Paused);
|
|
|
|
|
break;
|
|
|
|
|
case Mch_RESULTS:
|
|
|
|
|
/* Write answers with results */
|
2019-10-23 01:30:11 +02:00
|
|
|
|
Mch_WriteAnswersMatchResult (Match,
|
2019-10-21 21:36:31 +02:00
|
|
|
|
"MCH_TCH_ANS",
|
2019-09-16 00:15:40 +02:00
|
|
|
|
true); // Show result
|
2019-09-14 12:59:34 +02:00
|
|
|
|
break;
|
2019-12-12 09:14:26 +01:00
|
|
|
|
default:
|
2019-12-10 21:52:22 +01:00
|
|
|
|
/* Don't write anything */
|
|
|
|
|
break;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
HTM_DIV_End (); // Bottom
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 01:30:11 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************* Write answers of a question when viewing a match **************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_WriteAnswersMatchResult (const struct Match *Match,
|
2019-10-23 01:30:11 +02:00
|
|
|
|
const char *Class,bool ShowResult)
|
|
|
|
|
{
|
|
|
|
|
/***** Write answer depending on type *****/
|
|
|
|
|
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE)
|
|
|
|
|
Tst_WriteChoiceAnsViewMatch (Match->MchCod,Match->Status.QstInd,Match->Status.QstCod,
|
|
|
|
|
Match->Status.NumCols,Class,ShowResult);
|
|
|
|
|
else
|
|
|
|
|
Ale_ShowAlert (Ale_ERROR,"Type of answer not valid in a game.");
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***** Show question and its answers when playing a match (as a student) *****/
|
|
|
|
|
/*****************************************************************************/
|
2019-12-04 22:22:42 +01:00
|
|
|
|
// Return true on valid question, false on invalid question
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static bool Mch_ShowQuestionAndAnswersStd (const struct Match *Match,
|
2019-12-03 02:46:46 +01:00
|
|
|
|
const struct Mch_UsrAnswer *UsrAnswer,
|
|
|
|
|
Mch_Update_t Update)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumOptions;
|
|
|
|
|
unsigned NumOpt;
|
2019-11-11 00:15:44 +01:00
|
|
|
|
char *Class;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-04 22:22:42 +01:00
|
|
|
|
/***** Trivial check: this question must be valid for games *****/
|
|
|
|
|
if (!Tst_CheckIfQuestionIsValidForGame (Match->Status.QstCod))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/***** Get number of options in this question *****/
|
|
|
|
|
NumOptions = Tst_GetNumAnswersQst (Match->Status.QstCod);
|
|
|
|
|
|
|
|
|
|
/***** Begin table *****/
|
|
|
|
|
HTM_TABLE_BeginWidePadding (8);
|
|
|
|
|
|
|
|
|
|
for (NumOpt = 0;
|
|
|
|
|
NumOpt < NumOptions;
|
|
|
|
|
NumOpt++)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-04 22:22:42 +01:00
|
|
|
|
/***** Start row *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-04 22:22:42 +01:00
|
|
|
|
/***** Write letter for this option *****/
|
|
|
|
|
/* Begin table cell */
|
|
|
|
|
HTM_TD_Begin ("class=\"MCH_STD_CELL\"");
|
|
|
|
|
|
|
|
|
|
/* Form with button.
|
|
|
|
|
Sumitting onmousedown instead of default onclick
|
|
|
|
|
is necessary in order to be fast
|
|
|
|
|
and not lose clicks due to refresh */
|
|
|
|
|
Frm_StartForm (ActAnsMchQstStd);
|
|
|
|
|
Mch_PutParamMchCod (Match->MchCod); // Current match being played
|
|
|
|
|
Gam_PutParamQstInd (Match->Status.QstInd); // Current question index shown
|
|
|
|
|
Mch_PutParamNumOpt (NumOpt); // Number of button
|
|
|
|
|
|
|
|
|
|
if (asprintf (&Class,"MCH_STD_BUTTON%s BT_%c",
|
|
|
|
|
UsrAnswer->NumOpt == (int) NumOpt && // Student's answer
|
|
|
|
|
Update == Mch_CHANGE_STATUS_BY_STUDENT ? " MCH_STD_ANSWER_SELECTED" :
|
|
|
|
|
"",
|
|
|
|
|
'A' + (char) NumOpt) < 0)
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_BUTTON_OnMouseDown_Begin (NULL,Class);
|
2019-12-04 22:22:42 +01:00
|
|
|
|
HTM_TxtF ("%c",'a' + (char) NumOpt);
|
|
|
|
|
HTM_BUTTON_End ();
|
|
|
|
|
free (Class);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-04 22:22:42 +01:00
|
|
|
|
Frm_EndForm ();
|
2019-12-04 01:19:31 +01:00
|
|
|
|
|
2019-12-04 22:22:42 +01:00
|
|
|
|
/* End table cell */
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
|
|
|
|
/***** End row *****/
|
|
|
|
|
HTM_TR_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
2019-12-04 22:22:42 +01:00
|
|
|
|
|
|
|
|
|
/***** End table *****/
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
|
|
|
|
|
return true;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 01:01:35 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/***************************** Show match scores *****************************/
|
2019-10-01 01:01:35 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-10-21 21:36:31 +02:00
|
|
|
|
#define Mch_NUM_ROWS_SCORE 50
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
2019-12-05 19:54:28 +01:00
|
|
|
|
static void Mch_ShowMatchScore (const struct Match *Match)
|
2019-10-01 01:01:35 +02:00
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
2019-10-21 13:36:28 +02:00
|
|
|
|
unsigned NumScores;
|
|
|
|
|
unsigned NumScore;
|
|
|
|
|
double MinScore;
|
|
|
|
|
double MaxScore;
|
|
|
|
|
double Range;
|
|
|
|
|
double NumRowsPerScorePoint;
|
|
|
|
|
double Score;
|
|
|
|
|
unsigned MaxUsrs = 0;
|
|
|
|
|
unsigned NumUsrs;
|
|
|
|
|
unsigned NumRowForThisScore;
|
2019-10-01 01:01:35 +02:00
|
|
|
|
unsigned NumRow;
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
|
|
|
|
/***** Get minimum and maximum scores *****/
|
|
|
|
|
Gam_GetScoreRange (Match->GamCod,&MinScore,&MaxScore);
|
|
|
|
|
Range = MaxScore - MinScore;
|
|
|
|
|
if (Range == 0.0)
|
|
|
|
|
return;
|
|
|
|
|
NumRowsPerScorePoint = (double) Mch_NUM_ROWS_SCORE / Range;
|
|
|
|
|
|
|
|
|
|
/***** Get maximum number of users *****/
|
|
|
|
|
if (DB_QuerySELECT (&mysql_res,"can not get max users",
|
|
|
|
|
"SELECT MAX(NumUsrs)"
|
|
|
|
|
" FROM "
|
|
|
|
|
"(SELECT COUNT(*) AS NumUsrs" // row[1]
|
|
|
|
|
" FROM mch_results"
|
|
|
|
|
" WHERE MchCod=%ld"
|
|
|
|
|
" GROUP BY Score"
|
|
|
|
|
" ORDER BY Score) AS Scores",
|
|
|
|
|
Match->MchCod))
|
2019-10-01 01:01:35 +02:00
|
|
|
|
{
|
2019-10-21 13:36:28 +02:00
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
2019-10-01 01:01:35 +02:00
|
|
|
|
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/* Get maximum number of users (row[0]) *****/
|
|
|
|
|
if (row)
|
|
|
|
|
if (row[0])
|
|
|
|
|
if (sscanf (row[0],"%u",&MaxUsrs) != 1)
|
|
|
|
|
MaxUsrs = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free structure that stores the query result */
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
|
|
|
|
|
/***** Get scores from database *****/
|
|
|
|
|
NumScores = (unsigned)
|
|
|
|
|
DB_QuerySELECT (&mysql_res,"can not get scores",
|
|
|
|
|
"SELECT Score," // row[0]
|
|
|
|
|
"COUNT(*) AS NumUsrs" // row[1]
|
|
|
|
|
" FROM mch_results"
|
|
|
|
|
" WHERE MchCod=%ld"
|
|
|
|
|
" GROUP BY Score"
|
|
|
|
|
" ORDER BY Score DESC",
|
|
|
|
|
Match->MchCod);
|
|
|
|
|
|
|
|
|
|
/***** Begin table ****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TABLE_BeginWide ();
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
|
|
|
|
/***** Get and draw scores *****/
|
|
|
|
|
for (NumScore = 0, NumRow = 0;
|
|
|
|
|
NumScore < NumScores;
|
|
|
|
|
NumScore++)
|
2019-10-01 01:01:35 +02:00
|
|
|
|
{
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/***** Get score and number of users from database *****/
|
2019-10-01 01:01:35 +02:00
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
|
|
|
|
|
/* Get score (row[0]) */
|
2019-10-21 13:36:28 +02:00
|
|
|
|
Str_SetDecimalPointToUS (); // To get the decimal point as a dot
|
|
|
|
|
if (sscanf (row[0],"%lf",&Score) != 1)
|
|
|
|
|
Score = 0.0;
|
2019-10-01 01:01:35 +02:00
|
|
|
|
Str_SetDecimalPointToLocal (); // Return to local system
|
|
|
|
|
|
|
|
|
|
/* Get number of users (row[1]) *****/
|
2019-10-21 13:36:28 +02:00
|
|
|
|
if (sscanf (row[1],"%u",&NumUsrs) != 1)
|
|
|
|
|
NumUsrs = 0;
|
|
|
|
|
|
|
|
|
|
/***** Draw empty rows until reaching the adequate row *****/
|
|
|
|
|
NumRowForThisScore = (unsigned) ((MaxScore - Score) * NumRowsPerScorePoint);
|
2019-10-21 16:43:18 +02:00
|
|
|
|
if (NumRowForThisScore == Mch_NUM_ROWS_SCORE)
|
|
|
|
|
NumRowForThisScore = Mch_NUM_ROWS_SCORE - 1;
|
2019-10-21 13:36:28 +02:00
|
|
|
|
for (;
|
|
|
|
|
NumRow < NumRowForThisScore;
|
|
|
|
|
NumRow++)
|
2019-12-14 01:31:32 +01:00
|
|
|
|
Mch_DrawEmptyScoreRow (NumRow,MinScore,MaxScore);
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
|
|
|
|
/***** Draw row for this score *****/
|
2019-10-21 21:36:31 +02:00
|
|
|
|
Mch_DrawScoreRow (Score,MinScore,MaxScore,NumRow,NumUsrs,MaxUsrs);
|
2019-10-21 13:36:28 +02:00
|
|
|
|
NumRow++;
|
2019-10-01 01:01:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/***** Draw final empty rows *****/
|
2019-10-01 01:01:35 +02:00
|
|
|
|
for (;
|
2019-10-21 13:36:28 +02:00
|
|
|
|
NumRow < Mch_NUM_ROWS_SCORE;
|
2019-10-01 01:01:35 +02:00
|
|
|
|
NumRow++)
|
2019-12-14 01:31:32 +01:00
|
|
|
|
Mch_DrawEmptyScoreRow (NumRow,MinScore,MaxScore);
|
2019-10-01 01:01:35 +02:00
|
|
|
|
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/***** End table *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TABLE_End ();
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*************************** Draw empty score row ****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_DrawEmptyScoreRow (unsigned NumRow,double MinScore,double MaxScore)
|
2019-10-21 13:36:28 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Draw row *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
|
|
|
|
/* Write score */
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"MCH_SCO_SCO\"");
|
2019-10-21 13:36:28 +02:00
|
|
|
|
if (NumRow == 0)
|
|
|
|
|
{
|
2020-01-11 15:22:02 +01:00
|
|
|
|
HTM_DoubleFewDigits (MaxScore);
|
2019-11-14 08:59:11 +01:00
|
|
|
|
HTM_NBSP ();
|
2019-10-01 01:01:35 +02:00
|
|
|
|
}
|
2019-10-21 13:36:28 +02:00
|
|
|
|
else if (NumRow == Mch_NUM_ROWS_SCORE - 1)
|
|
|
|
|
{
|
2020-01-11 15:22:02 +01:00
|
|
|
|
HTM_DoubleFewDigits (MinScore);
|
2019-11-14 08:59:11 +01:00
|
|
|
|
HTM_NBSP ();
|
2019-10-21 13:36:28 +02:00
|
|
|
|
}
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-10-01 01:01:35 +02:00
|
|
|
|
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/* Empty column with bar and number of users */
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"MCH_SCO_NUM%s\"",Mch_GetClassBorder (NumRow));
|
|
|
|
|
HTM_TD_End ();
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_End ();
|
2019-10-21 13:36:28 +02:00
|
|
|
|
}
|
2019-10-01 01:01:35 +02:00
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************************* Draw score row ******************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-10-21 15:07:00 +02:00
|
|
|
|
static void Mch_DrawScoreRow (double Score,double MinScore,double MaxScore,
|
2019-10-21 21:36:31 +02:00
|
|
|
|
unsigned NumRow,unsigned NumUsrs,unsigned MaxUsrs)
|
2019-10-21 13:36:28 +02:00
|
|
|
|
{
|
2019-10-21 21:36:31 +02:00
|
|
|
|
extern const char *Txt_ROLES_SINGUL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
|
|
|
|
|
extern const char *Txt_ROLES_PLURAL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
|
2019-10-21 15:07:00 +02:00
|
|
|
|
unsigned Color;
|
2019-10-21 13:36:28 +02:00
|
|
|
|
unsigned BarWidth;
|
2019-10-30 23:55:49 +01:00
|
|
|
|
char *Icon;
|
2019-10-01 01:01:35 +02:00
|
|
|
|
|
2019-10-21 15:07:00 +02:00
|
|
|
|
/***** Compute color *****/
|
|
|
|
|
/*
|
|
|
|
|
+----------------- MaxScore
|
|
|
|
|
| score9_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score8_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score7_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score6_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score5_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score4_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score3_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score2_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score1_1x1.png
|
|
|
|
|
+-----------------
|
|
|
|
|
| score0_1x1.png
|
|
|
|
|
+----------------- MinScore
|
|
|
|
|
*/
|
|
|
|
|
Color = (unsigned) (((Score - MinScore) / (MaxScore - MinScore)) * 10.0);
|
2019-10-21 16:43:18 +02:00
|
|
|
|
if (Color == 10)
|
2019-10-21 15:07:00 +02:00
|
|
|
|
Color = 9;
|
|
|
|
|
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/***** Compute bar width *****/
|
|
|
|
|
if (MaxUsrs > 0)
|
2019-10-01 01:01:35 +02:00
|
|
|
|
{
|
2019-10-21 13:36:28 +02:00
|
|
|
|
BarWidth = (unsigned) (((NumUsrs * 95.0) / MaxUsrs) + 0.5);
|
|
|
|
|
if (BarWidth == 0)
|
|
|
|
|
BarWidth = 1;
|
2019-10-01 01:01:35 +02:00
|
|
|
|
}
|
2019-10-21 13:36:28 +02:00
|
|
|
|
else
|
|
|
|
|
BarWidth = 0;
|
2019-10-01 01:01:35 +02:00
|
|
|
|
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/***** Draw row *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2019-10-01 01:01:35 +02:00
|
|
|
|
|
2019-10-21 13:36:28 +02:00
|
|
|
|
/* Write score */
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"MCH_SCO_SCO\"");
|
2020-01-11 15:22:02 +01:00
|
|
|
|
HTM_DoubleFewDigits (Score);
|
2019-11-14 08:59:11 +01:00
|
|
|
|
HTM_NBSP ();
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
|
|
|
|
/* Draw bar and write number of users for this score */
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"MCH_SCO_NUM%s\"",Mch_GetClassBorder (NumRow));
|
2019-10-30 23:55:49 +01:00
|
|
|
|
if (asprintf (&Icon,"score%u_1x1.png",Color) < 0) // Background
|
|
|
|
|
Lay_NotEnoughMemoryExit ();
|
2019-12-30 21:47:07 +01:00
|
|
|
|
HTM_IMG (Cfg_URL_ICON_PUBLIC,Icon,
|
|
|
|
|
Str_BuildStringLongStr ((long) NumUsrs,
|
|
|
|
|
NumUsrs == 1 ? Txt_ROLES_SINGUL_abc[Rol_STD][Usr_SEX_UNKNOWN] :
|
|
|
|
|
Txt_ROLES_PLURAL_abc[Rol_STD][Usr_SEX_UNKNOWN]),
|
2019-10-30 23:55:49 +01:00
|
|
|
|
"class=\"MCH_SCO_BAR\" style=\"width:%u%%;\"",BarWidth);
|
2019-12-30 21:47:07 +01:00
|
|
|
|
Str_FreeString ();
|
2019-11-06 19:45:20 +01:00
|
|
|
|
free (Icon);
|
2019-12-30 21:47:07 +01:00
|
|
|
|
HTM_TxtF (" %u",NumUsrs);
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-10-21 13:36:28 +02:00
|
|
|
|
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_End ();
|
2019-10-01 01:01:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-24 01:41:51 +02:00
|
|
|
|
/****** Write parameter with number of option (button) pressed by user *******/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-10-21 21:36:31 +02:00
|
|
|
|
static const char *Mch_GetClassBorder (unsigned NumRow)
|
|
|
|
|
{
|
|
|
|
|
return NumRow == 0 ? " MCH_SCO_TOP" :
|
|
|
|
|
(NumRow == Mch_NUM_ROWS_SCORE - 1 ? " MCH_SCO_BOT" :
|
|
|
|
|
" MCH_SCO_MID");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****** Write parameter with number of option (button) pressed by user *******/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-24 01:41:51 +02:00
|
|
|
|
static void Mch_PutParamNumOpt (unsigned NumOpt)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-11-03 13:19:32 +01:00
|
|
|
|
Par_PutHiddenParamUnsigned (NULL,"NumOpt",NumOpt);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-09-24 01:41:51 +02:00
|
|
|
|
/******* Get parameter with number of option (button) pressed by user ********/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-24 01:41:51 +02:00
|
|
|
|
static unsigned Mch_GetParamNumOpt (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-09-24 01:41:51 +02:00
|
|
|
|
long NumOpt;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-24 01:41:51 +02:00
|
|
|
|
NumOpt = Par_GetParToLong ("NumOpt");
|
|
|
|
|
if (NumOpt < 0)
|
|
|
|
|
Lay_ShowErrorAndExit ("Wrong number of option.");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-09-24 01:41:51 +02:00
|
|
|
|
return (unsigned) NumOpt;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************** Put a big button to do action ***********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-10-17 22:47:44 +02:00
|
|
|
|
static void Mch_PutBigButton (Act_Action_t NextAction,const char *Id,
|
|
|
|
|
long MchCod,const char *Icon,const char *Txt)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-10-20 22:00:28 +02:00
|
|
|
|
/***** Begin form *****/
|
2019-10-17 22:47:44 +02:00
|
|
|
|
Frm_StartFormId (NextAction,Id);
|
2019-09-22 13:54:11 +02:00
|
|
|
|
Mch_PutParamMchCod (MchCod);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Put icon with link *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BIGBUTTON_CONT\"");
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_BUTTON_SUBMIT_Begin (Txt,"BT_LINK MCH_BUTTON_ON ICO_BLACK",NULL);
|
2019-11-11 00:15:44 +01:00
|
|
|
|
HTM_TxtF ("<i class=\"%s\"></i>",Icon);
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** End form *****/
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************************** Put a big button hidden **************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-13 00:36:01 +01:00
|
|
|
|
static void Mch_PutBigButtonHidden (const char *Icon)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Put inactive icon *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BIGBUTTON_CONT\"");
|
|
|
|
|
HTM_BUTTON_BUTTON_Begin (NULL,"BT_LINK_OFF MCH_BUTTON_HIDDEN ICO_BLACK",NULL);
|
2019-11-11 00:15:44 +01:00
|
|
|
|
HTM_TxtF ("<i class=\"%s\"></i>",Icon);
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Put a big button to close window *********************/
|
|
|
|
|
/*****************************************************************************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
static void Mch_PutBigButtonClose (void)
|
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Close;
|
|
|
|
|
|
|
|
|
|
/***** Put icon with link *****/
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_BIGBUTTON_CONT\"");
|
|
|
|
|
HTM_BUTTON_BUTTON_Begin (Txt_Close,"BT_LINK MCH_BUTTON_ON ICO_DARKRED","window.close();");
|
2019-11-11 00:15:44 +01:00
|
|
|
|
HTM_TxtF ("<i class=\"%s\"></i>",Mch_ICON_CLOSE);
|
2019-12-04 01:19:31 +01:00
|
|
|
|
HTM_BUTTON_End ();
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************************** Show wait image ******************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_ShowWaitImage (const char *Txt)
|
|
|
|
|
{
|
2019-12-13 00:36:01 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_WAIT_CONT\"");
|
2019-10-29 21:41:54 +01:00
|
|
|
|
Ico_PutIcon ("wait.gif",Txt,"MCH_WAIT_IMG");
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**************************** Remove old players *****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void Mch_RemoveOldPlayers (void)
|
|
|
|
|
{
|
2019-10-01 21:18:53 +02:00
|
|
|
|
/***** Delete matches not being played by teacher *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
DB_QueryDELETE ("can not update matches as not being played",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"DELETE FROM mch_playing"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE TS<FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)",
|
2019-10-01 21:18:53 +02:00
|
|
|
|
Cfg_SECONDS_TO_REFRESH_MATCH_TCH*3);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-10-01 21:18:53 +02:00
|
|
|
|
/***** Delete players (students) who have left matches *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
DB_QueryDELETE ("can not update match players",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"DELETE FROM mch_players"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE TS<FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)",
|
2019-10-01 21:18:53 +02:00
|
|
|
|
Cfg_SECONDS_TO_REFRESH_MATCH_STD*3);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Update match as being played *************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_UpdateMatchAsBeingPlayed (long MchCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Insert match as being played *****/
|
|
|
|
|
DB_QueryREPLACE ("can not set match as being played",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"REPLACE mch_playing (MchCod) VALUE (%ld)",
|
2019-09-14 12:59:34 +02:00
|
|
|
|
MchCod);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**************** Update match as paused, not being played *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_SetMatchAsNotBeingPlayed (long MchCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Delete all match players ******/
|
|
|
|
|
DB_QueryDELETE ("can not update match players",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"DELETE FROM mch_players"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE MchCod=%ld",
|
|
|
|
|
MchCod);
|
|
|
|
|
|
|
|
|
|
/***** Delete match as being played ******/
|
|
|
|
|
DB_QueryDELETE ("can not set match as not being played",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"DELETE FROM mch_playing"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE MchCod=%ld",
|
|
|
|
|
MchCod);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************** Get if match is being played ************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static bool Mch_GetIfMatchIsBeingPlayed (long MchCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Get if a match is being played or not *****/
|
|
|
|
|
return
|
|
|
|
|
(bool) (DB_QueryCOUNT ("can not get if match is being played",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"SELECT COUNT(*) FROM mch_playing"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" WHERE MchCod=%ld",
|
|
|
|
|
MchCod) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-14 01:31:32 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*************************** Get number of players ***************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
static void Mch_GetNumPlayers (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Get number of players who are playing a match *****/
|
2019-09-17 01:37:07 +02:00
|
|
|
|
Match->Status.NumPlayers =
|
|
|
|
|
(unsigned) DB_QueryCOUNT ("can not get number of players",
|
|
|
|
|
"SELECT COUNT(*) FROM mch_players"
|
|
|
|
|
" WHERE MchCod=%ld",
|
|
|
|
|
Match->MchCod);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-02 09:57:17 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************* Register me as a player in a match **********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
// Return true on success
|
|
|
|
|
|
|
|
|
|
bool Mch_RegisterMeAsPlayerInMatch (struct Match *Match)
|
|
|
|
|
{
|
|
|
|
|
/***** Trivial check: match code must be > 0 *****/
|
|
|
|
|
if (Match->MchCod <= 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/***** Trivial check: match must be being played *****/
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (!Match->Status.Playing) // Match is paused, not being played
|
2019-12-02 09:57:17 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/***** Trivial check: match must not be over *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
if (Match->Status.Showing == Mch_END) // Match over
|
2019-12-02 09:57:17 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/***** Trivial check: only a student can join a match *****/
|
|
|
|
|
if (Gbl.Usrs.Me.Role.Logged != Rol_STD) // I am not logged as student
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/***** Insert me as match player *****/
|
|
|
|
|
DB_QueryREPLACE ("can not insert match player",
|
|
|
|
|
"REPLACE mch_players (MchCod,UsrCod) VALUES (%ld,%ld)",
|
|
|
|
|
Match->MchCod,Gbl.Usrs.Me.UsrDat.UsrCod);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************** Get code of match being played ***********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_GetMatchBeingPlayed (void)
|
|
|
|
|
{
|
|
|
|
|
/***** Get match code ****/
|
2019-09-22 13:54:11 +02:00
|
|
|
|
if ((Gbl.Games.MchCodBeingPlayed = Mch_GetParamMchCod ()) == -1L)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Lay_ShowErrorAndExit ("Code of match is missing.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-12-03 02:46:46 +01:00
|
|
|
|
/********************* Show match being played as student ********************/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
void Mch_JoinMatchAsStd (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-12-03 02:46:46 +01:00
|
|
|
|
Mch_ShowMatchStatusForStd (&Match,Mch_CHANGE_STATUS_BY_STUDENT);
|
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****** Remove student's answer to a question and show match as student ******/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-10 21:52:22 +01:00
|
|
|
|
void Mch_RemoveMyQuestionAnswer (void)
|
2019-12-03 02:46:46 +01:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
unsigned QstInd;
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Get question index from form *****/
|
|
|
|
|
QstInd = Gam_GetParamQstInd ();
|
|
|
|
|
|
|
|
|
|
/***** Check that teacher's screen is showing answers
|
|
|
|
|
and question index is the current one being played *****/
|
2019-12-03 15:39:48 +01:00
|
|
|
|
if (Match.Status.Playing && // Match is being played
|
|
|
|
|
Match.Status.Showing == Mch_ANSWERS && // Teacher's screen is showing answers
|
2019-12-03 02:46:46 +01:00
|
|
|
|
QstInd == Match.Status.QstInd) // Removing answer to the current question being played
|
|
|
|
|
/***** Remove answer to this question *****/
|
2019-12-10 21:52:22 +01:00
|
|
|
|
Mch_RemoveMyAnswerToMatchQuestion (&Match);
|
2019-12-03 02:46:46 +01:00
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
|
|
|
|
Mch_ShowMatchStatusForStd (&Match,Mch_CHANGE_STATUS_BY_STUDENT);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-13 23:38:29 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Start match countdown (by a teacher) *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_StartCountdown (void)
|
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
long NewCountdown;
|
|
|
|
|
|
|
|
|
|
/***** Get countdown parameter ****/
|
|
|
|
|
NewCountdown = Par_GetParToLong ("Countdown");
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Start countdown *****/
|
|
|
|
|
Match.Status.Countdown = NewCountdown;
|
|
|
|
|
|
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
|
|
|
|
Mch_ShowRefreshablePartTch (&Match);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Refresh match for a teacher via AJAX *********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_RefreshMatchTch (void)
|
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
2019-12-12 18:24:23 +01:00
|
|
|
|
enum {REFRESH_LEFT,REFRESH_ALL} WhatToRefresh;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
if (!Gbl.Session.IsOpen) // If session has been closed, do not write anything
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/***** Remove old players.
|
2019-10-01 21:18:53 +02:00
|
|
|
|
This function must be called by a teacher
|
|
|
|
|
before getting match status. *****/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Mch_RemoveOldPlayers ();
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
2019-12-12 18:24:23 +01:00
|
|
|
|
/***** Update countdown *****/
|
|
|
|
|
// If current countdown is < 0 ==> no countdown in progress
|
|
|
|
|
WhatToRefresh = REFRESH_LEFT;
|
|
|
|
|
if (Match.Status.Playing && // Match is being played
|
|
|
|
|
Match.Status.Countdown >= 0) // Countdown in progress
|
|
|
|
|
{
|
|
|
|
|
/* Decrease countdown */
|
|
|
|
|
Match.Status.Countdown -= Cfg_SECONDS_TO_REFRESH_MATCH_TCH;
|
|
|
|
|
|
|
|
|
|
/* On countdown reached, set match status to next (forward) status */
|
|
|
|
|
if (Match.Status.Countdown <= 0) // End of countdown reached
|
|
|
|
|
{
|
|
|
|
|
Mch_SetMatchStatusToNext (&Match);
|
|
|
|
|
WhatToRefresh = REFRESH_ALL; // Refresh the whole page
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Update match status in database *****/
|
|
|
|
|
Mch_UpdateMatchStatusInDB (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Update elapsed time in this question *****/
|
|
|
|
|
Mch_UpdateElapsedTimeInQuestion (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-12-12 18:24:23 +01:00
|
|
|
|
switch (WhatToRefresh)
|
|
|
|
|
{
|
|
|
|
|
case REFRESH_LEFT: // Refresh only left part
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_Txt ("match_left|0|"); // 0 ==> do not evaluate MatJax scripts after updating HTML
|
2019-12-12 18:24:23 +01:00
|
|
|
|
Mch_ShowRefreshablePartTch (&Match);
|
|
|
|
|
break;
|
|
|
|
|
case REFRESH_ALL: // Refresh the whole page
|
2019-12-14 01:31:32 +01:00
|
|
|
|
HTM_Txt ("match|1|"); // 1 ==> evaluate MatJax scripts after updating HTML
|
2019-12-12 18:24:23 +01:00
|
|
|
|
Mch_ShowMatchStatusForTch (&Match);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*************** Refresh current game for a student via AJAX *****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void Mch_RefreshMatchStd (void)
|
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
|
|
|
|
|
if (!Gbl.Session.IsOpen) // If session has been closed, do not write anything
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-12-03 02:46:46 +01:00
|
|
|
|
Mch_ShowMatchStatusForStd (&Match,Mch_REFRESH_STATUS_BY_SERVER);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**** Receive previous question answer in a match question from database *****/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-28 02:31:42 +02:00
|
|
|
|
void Mch_GetQstAnsFromDB (long MchCod,long UsrCod,unsigned QstInd,
|
|
|
|
|
struct Mch_UsrAnswer *UsrAnswer)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
unsigned NumRows;
|
2019-09-24 01:41:51 +02:00
|
|
|
|
|
|
|
|
|
/***** Set default values for number of option and answer index *****/
|
|
|
|
|
UsrAnswer->NumOpt = -1; // < 0 ==> no answer selected
|
|
|
|
|
UsrAnswer->AnsInd = -1; // < 0 ==> no answer selected
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Get student's answer *****/
|
2019-09-24 01:41:51 +02:00
|
|
|
|
NumRows = (unsigned) DB_QuerySELECT (&mysql_res,"can not get user's answer to a match question",
|
|
|
|
|
"SELECT NumOpt," // row[0]
|
|
|
|
|
"AnsInd" // row[1]
|
|
|
|
|
" FROM mch_answers"
|
2019-09-23 19:17:12 +02:00
|
|
|
|
" WHERE MchCod=%ld"
|
|
|
|
|
" AND UsrCod=%ld"
|
|
|
|
|
" AND QstInd=%u",
|
|
|
|
|
MchCod,UsrCod,QstInd);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
if (NumRows) // Answer found...
|
|
|
|
|
{
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
2019-09-24 01:41:51 +02:00
|
|
|
|
|
|
|
|
|
/***** Get number of option index (row[0]) *****/
|
|
|
|
|
if (sscanf (row[0],"%d",&(UsrAnswer->NumOpt)) != 1)
|
|
|
|
|
Lay_ShowErrorAndExit ("Error when getting student's answer to a match question.");
|
|
|
|
|
|
|
|
|
|
/***** Get answer index (row[1]) *****/
|
|
|
|
|
if (sscanf (row[1],"%d",&(UsrAnswer->AnsInd)) != 1)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
Lay_ShowErrorAndExit ("Error when getting student's answer to a match question.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********* Receive question answer from student when playing a match *********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-29 21:33:27 +02:00
|
|
|
|
void Mch_ReceiveQuestionAnswer (void)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct Match Match;
|
|
|
|
|
unsigned QstInd;
|
2019-09-24 01:41:51 +02:00
|
|
|
|
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION];
|
|
|
|
|
struct Mch_UsrAnswer PreviousUsrAnswer;
|
|
|
|
|
struct Mch_UsrAnswer UsrAnswer;
|
2019-09-23 01:48:28 +02:00
|
|
|
|
unsigned NumQsts;
|
|
|
|
|
unsigned NumQstsNotBlank;
|
|
|
|
|
double TotalScore;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Get data of the match from database *****/
|
|
|
|
|
Match.MchCod = Gbl.Games.MchCodBeingPlayed;
|
|
|
|
|
Mch_GetDataOfMatchByCod (&Match);
|
|
|
|
|
|
|
|
|
|
/***** Get question index from form *****/
|
|
|
|
|
QstInd = Gam_GetParamQstInd ();
|
|
|
|
|
|
2019-10-01 23:05:07 +02:00
|
|
|
|
/***** Check that teacher's screen is showing answers
|
|
|
|
|
and question index is the current one being played *****/
|
|
|
|
|
if (Match.Status.Showing == Mch_ANSWERS && // Teacher's screen is showing answers
|
|
|
|
|
QstInd == Match.Status.QstInd) // Receiving an answer to the current question being played
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-03 02:46:46 +01:00
|
|
|
|
/***** Get indexes for this question from database *****/
|
|
|
|
|
Mch_GetIndexes (Match.MchCod,Match.Status.QstInd,Indexes);
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/***** Get answer index *****/
|
2019-09-24 01:41:51 +02:00
|
|
|
|
/*
|
|
|
|
|
Indexes[4] = {0,3,1,2}
|
|
|
|
|
+-------+--------+----------+---------+
|
|
|
|
|
| Button | Option | Answer | Correct |
|
|
|
|
|
| letter | number | index | |
|
|
|
|
|
| screen | screen | database | |
|
|
|
|
|
+--------+--------+----------+---------+
|
|
|
|
|
| a | 0 | 0 | |
|
|
|
|
|
| b | 1 | 3 | |
|
|
|
|
|
| c | 2 | 1 | Y | <---- User press button #2 (index = 1, correct)
|
|
|
|
|
| d | 3 | 2 | |
|
|
|
|
|
+--------+--------+----------+---------+
|
|
|
|
|
UsrAnswer.NumOpt = 2
|
|
|
|
|
UsrAnswer.AnsInd = 1
|
|
|
|
|
*/
|
|
|
|
|
UsrAnswer.NumOpt = Mch_GetParamNumOpt ();
|
|
|
|
|
UsrAnswer.AnsInd = Indexes[UsrAnswer.NumOpt];
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Get previous student's answer to this question
|
|
|
|
|
(<0 ==> no answer) *****/
|
2019-12-03 02:46:46 +01:00
|
|
|
|
Mch_GetQstAnsFromDB (Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,Match.Status.QstInd,
|
2019-09-24 01:41:51 +02:00
|
|
|
|
&PreviousUsrAnswer);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Store student's answer *****/
|
2019-12-03 02:46:46 +01:00
|
|
|
|
if (UsrAnswer.NumOpt >= 0 &&
|
|
|
|
|
UsrAnswer.AnsInd >= 0 &&
|
|
|
|
|
UsrAnswer.AnsInd != PreviousUsrAnswer.AnsInd)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
DB_QueryREPLACE ("can not register your answer to the match question",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"REPLACE mch_answers"
|
2019-09-24 01:41:51 +02:00
|
|
|
|
" (MchCod,UsrCod,QstInd,NumOpt,AnsInd)"
|
2019-09-14 12:59:34 +02:00
|
|
|
|
" VALUES"
|
2019-09-24 01:41:51 +02:00
|
|
|
|
" (%ld,%ld,%u,%d,%d)",
|
2019-12-03 02:46:46 +01:00
|
|
|
|
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,Match.Status.QstInd,
|
2019-09-24 01:41:51 +02:00
|
|
|
|
UsrAnswer.NumOpt,
|
|
|
|
|
UsrAnswer.AnsInd);
|
2019-09-23 01:48:28 +02:00
|
|
|
|
|
|
|
|
|
/***** Update student's match result *****/
|
2019-09-30 01:26:19 +02:00
|
|
|
|
McR_GetMatchResultQuestionsFromDB (Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,
|
2019-09-24 21:29:01 +02:00
|
|
|
|
&NumQsts,&NumQstsNotBlank);
|
|
|
|
|
TotalScore = Mch_ComputeScore (NumQsts);
|
2019-09-24 09:24:36 +02:00
|
|
|
|
|
2019-09-23 01:48:28 +02:00
|
|
|
|
Str_SetDecimalPointToUS (); // To print the floating point as a dot
|
2019-09-23 09:03:55 +02:00
|
|
|
|
if (DB_QueryCOUNT ("can not get if match result exists",
|
|
|
|
|
"SELECT COUNT(*) FROM mch_results"
|
|
|
|
|
" WHERE MchCod=%ld AND UsrCod=%ld",
|
|
|
|
|
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod)) // Result exists
|
|
|
|
|
/* Update result */
|
|
|
|
|
DB_QueryUPDATE ("can not update match result",
|
|
|
|
|
"UPDATE mch_results"
|
|
|
|
|
" SET EndTime=NOW(),"
|
|
|
|
|
"NumQsts=%u,"
|
|
|
|
|
"NumQstsNotBlank=%u,"
|
2020-01-11 15:22:02 +01:00
|
|
|
|
"Score='%.15lg'"
|
2019-09-24 01:41:51 +02:00
|
|
|
|
" WHERE MchCod=%ld AND UsrCod=%ld",
|
2019-09-23 09:03:55 +02:00
|
|
|
|
NumQsts,NumQstsNotBlank,TotalScore,
|
|
|
|
|
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod);
|
|
|
|
|
else // Result doesn't exist
|
|
|
|
|
/* Create result */
|
|
|
|
|
DB_QueryINSERT ("can not create match result",
|
|
|
|
|
"INSERT mch_results "
|
|
|
|
|
"(MchCod,UsrCod,StartTime,EndTime,NumQsts,NumQstsNotBlank,Score)"
|
|
|
|
|
" VALUES "
|
|
|
|
|
"(%ld," // MchCod
|
|
|
|
|
"%ld," // UsrCod
|
|
|
|
|
"NOW()," // StartTime
|
|
|
|
|
"NOW()," // EndTime
|
|
|
|
|
"%u," // NumQsts
|
|
|
|
|
"%u," // NumQstsNotBlank
|
2020-01-11 15:22:02 +01:00
|
|
|
|
"'%.15lg')", // Score
|
2019-09-23 09:03:55 +02:00
|
|
|
|
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
|
|
|
NumQsts,NumQstsNotBlank,TotalScore);
|
2019-09-23 01:48:28 +02:00
|
|
|
|
Str_SetDecimalPointToLocal (); // Return to local system
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Show current match status *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("id=\"match\" class=\"MCH_CONT\"");
|
2019-12-03 02:46:46 +01:00
|
|
|
|
Mch_ShowMatchStatusForStd (&Match,Mch_CHANGE_STATUS_BY_STUDENT);
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 02:46:46 +01:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********************* Remove answer to match question ***********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-10 21:52:22 +01:00
|
|
|
|
static void Mch_RemoveMyAnswerToMatchQuestion (const struct Match *Match)
|
2019-12-03 02:46:46 +01:00
|
|
|
|
{
|
|
|
|
|
DB_QueryDELETE ("can not remove your answer to the match question",
|
|
|
|
|
"DELETE FROM mch_answers"
|
|
|
|
|
" WHERE MchCod=%ld AND UsrCod=%ld AND QstInd=%u",
|
|
|
|
|
Match->MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,Match->Status.QstInd);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-23 01:48:28 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Compute match score for a student **********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-24 21:29:01 +02:00
|
|
|
|
static double Mch_ComputeScore (unsigned NumQsts)
|
2019-09-23 01:48:28 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumQst;
|
|
|
|
|
double ScoreThisQst;
|
|
|
|
|
bool AnswerIsNotBlank;
|
|
|
|
|
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
|
|
|
|
|
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION];
|
2019-09-24 21:29:01 +02:00
|
|
|
|
double TotalScore = 0.0;
|
2019-09-23 01:48:28 +02:00
|
|
|
|
|
2019-09-24 21:29:01 +02:00
|
|
|
|
for (NumQst = 0;
|
|
|
|
|
NumQst < NumQsts;
|
2019-09-23 19:17:12 +02:00
|
|
|
|
NumQst++)
|
2019-09-23 01:48:28 +02:00
|
|
|
|
{
|
2019-09-23 19:17:12 +02:00
|
|
|
|
/***** Get indexes for this question from string *****/
|
|
|
|
|
Tst_GetIndexesFromStr (Gbl.Test.StrIndexesOneQst[NumQst],Indexes);
|
|
|
|
|
|
|
|
|
|
/***** Get the user's answers for this question from string *****/
|
|
|
|
|
Tst_GetAnswersFromStr (Gbl.Test.StrAnswersOneQst[NumQst],AnswersUsr);
|
|
|
|
|
|
|
|
|
|
/***** Get correct answers of test question from database *****/
|
|
|
|
|
Tst_GetCorrectAnswersFromDB (Gbl.Test.QstCodes[NumQst]);
|
2019-09-23 01:48:28 +02:00
|
|
|
|
|
|
|
|
|
/***** Compute the total score of this question *****/
|
|
|
|
|
Tst_ComputeScoreQst (Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank);
|
|
|
|
|
|
|
|
|
|
/***** Compute total score *****/
|
2019-09-24 21:29:01 +02:00
|
|
|
|
TotalScore += ScoreThisQst;
|
2019-09-23 01:48:28 +02:00
|
|
|
|
}
|
2019-09-24 21:29:01 +02:00
|
|
|
|
|
|
|
|
|
return TotalScore;
|
2019-09-23 01:48:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
2019-09-16 00:15:40 +02:00
|
|
|
|
/*** Get number of users who selected this answer and draw proportional bar **/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-16 00:15:40 +02:00
|
|
|
|
void Mch_GetAndDrawBarNumUsrsWhoHaveChosenAns (long MchCod,unsigned QstInd,unsigned AnsInd,
|
2019-12-12 09:14:26 +01:00
|
|
|
|
unsigned NumRespondersQst,bool Correct)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-12 09:14:26 +01:00
|
|
|
|
unsigned NumRespondersAns;
|
2019-09-16 00:15:40 +02:00
|
|
|
|
|
|
|
|
|
/***** Get number of users who selected this answer *****/
|
2019-12-12 09:14:26 +01:00
|
|
|
|
NumRespondersAns = Mch_GetNumUsrsWhoHaveChosenAns (MchCod,QstInd,AnsInd);
|
2019-09-16 00:15:40 +02:00
|
|
|
|
|
|
|
|
|
/***** Show stats of this answer *****/
|
2019-12-12 09:14:26 +01:00
|
|
|
|
Mch_DrawBarNumUsrs (NumRespondersAns,NumRespondersQst,Correct);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-12-12 09:14:26 +01:00
|
|
|
|
/********** Get number of users who answered a question in a match ***********/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
unsigned Mch_GetNumUsrsWhoAnsweredQst (long MchCod,unsigned QstInd)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
2019-12-12 09:14:26 +01:00
|
|
|
|
/***** Get number of users who answered
|
|
|
|
|
a question in a match from database *****/
|
2019-09-16 00:15:40 +02:00
|
|
|
|
return
|
2019-12-12 09:14:26 +01:00
|
|
|
|
(unsigned) DB_QueryCOUNT ("can not get number of users who answered a question",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"SELECT COUNT(*) FROM mch_answers"
|
2019-09-16 00:15:40 +02:00
|
|
|
|
" WHERE MchCod=%ld AND QstInd=%u",
|
|
|
|
|
MchCod,QstInd);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2019-09-16 00:15:40 +02:00
|
|
|
|
/*** Get number of users who have chosen a given answer of a game question ***/
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-16 00:15:40 +02:00
|
|
|
|
static unsigned Mch_GetNumUsrsWhoHaveChosenAns (long MchCod,unsigned QstInd,unsigned AnsInd)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Get number of users who have chosen
|
|
|
|
|
an answer of a question from database *****/
|
2019-09-16 00:15:40 +02:00
|
|
|
|
return
|
|
|
|
|
(unsigned) DB_QueryCOUNT ("can not get number of users who have chosen an answer",
|
2019-09-17 01:37:07 +02:00
|
|
|
|
"SELECT COUNT(*) FROM mch_answers"
|
2019-09-16 00:15:40 +02:00
|
|
|
|
" WHERE MchCod=%ld AND QstInd=%u AND AnsInd=%u",
|
|
|
|
|
MchCod,QstInd,AnsInd);
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-17 20:44:29 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****** Get number of users who have answered any question in a match ********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static unsigned Mch_GetNumUsrsWhoHaveAnswerMch (long MchCod)
|
|
|
|
|
{
|
|
|
|
|
/***** Get number of users who have answered
|
|
|
|
|
any question in match from database *****/
|
|
|
|
|
return
|
2019-09-23 09:03:55 +02:00
|
|
|
|
(unsigned) DB_QueryCOUNT ("can not get number of users who have answered a match",
|
2019-09-17 20:44:29 +02:00
|
|
|
|
"SELECT COUNT(DISTINCT UsrCod) FROM mch_answers"
|
|
|
|
|
" WHERE MchCod=%ld",
|
|
|
|
|
MchCod);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 12:59:34 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Draw a bar with the percentage of answers *****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-09-16 00:15:40 +02:00
|
|
|
|
// #define Mch_MAX_BAR_WIDTH 400
|
|
|
|
|
#define Mch_MAX_BAR_WIDTH 100
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
2019-12-12 09:14:26 +01:00
|
|
|
|
static void Mch_DrawBarNumUsrs (unsigned NumRespondersAns,unsigned NumRespondersQst,bool Correct)
|
2019-09-14 12:59:34 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_of_PART_OF_A_TOTAL;
|
2019-09-16 00:15:40 +02:00
|
|
|
|
unsigned i;
|
2019-09-14 12:59:34 +02:00
|
|
|
|
unsigned BarWidth = 0;
|
|
|
|
|
|
2019-09-16 00:15:40 +02:00
|
|
|
|
/***** Start container *****/
|
2019-10-24 00:04:40 +02:00
|
|
|
|
HTM_DIV_Begin ("class=\"MCH_RESULT\"");
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Draw bar with a with proportional to the number of clicks *****/
|
2019-12-12 09:14:26 +01:00
|
|
|
|
if (NumRespondersAns && NumRespondersQst)
|
|
|
|
|
BarWidth = (unsigned) ((((double) NumRespondersAns * (double) Mch_MAX_BAR_WIDTH) /
|
|
|
|
|
(double) NumRespondersQst) + 0.5);
|
2019-09-16 00:15:40 +02:00
|
|
|
|
|
|
|
|
|
/***** Bar proportional to number of users *****/
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TABLE_BeginWide ();
|
|
|
|
|
HTM_TR_Begin ("class=\"MCH_RES_TR\"");
|
2019-09-16 00:15:40 +02:00
|
|
|
|
for (i = 0;
|
|
|
|
|
i < 100;
|
|
|
|
|
i++)
|
2019-10-07 17:36:41 +02:00
|
|
|
|
{
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"%s\"",
|
2019-10-21 21:36:31 +02:00
|
|
|
|
(i < BarWidth) ? (Correct ? "MCH_RES_CORRECT" :
|
|
|
|
|
"MCH_RES_WRONG") :
|
|
|
|
|
"MCH_RES_VOID");
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TD_End ();
|
2019-10-07 17:36:41 +02:00
|
|
|
|
}
|
2019-10-23 19:05:05 +02:00
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
HTM_TABLE_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
|
|
|
|
|
/***** Write the number of users *****/
|
2019-12-30 18:08:31 +01:00
|
|
|
|
if (NumRespondersQst)
|
|
|
|
|
HTM_TxtF ("%u (%u%% %s %u)",
|
|
|
|
|
NumRespondersAns,
|
|
|
|
|
(unsigned) ((((double) NumRespondersAns * 100.0) / (double) NumRespondersQst) + 0.5),
|
|
|
|
|
Txt_of_PART_OF_A_TOTAL,NumRespondersQst);
|
|
|
|
|
else
|
|
|
|
|
HTM_TxtF ("0 (0%% %s %u)",
|
|
|
|
|
Txt_of_PART_OF_A_TOTAL,NumRespondersQst);
|
2019-09-16 00:15:40 +02:00
|
|
|
|
|
|
|
|
|
/***** End container *****/
|
2019-10-23 20:07:56 +02:00
|
|
|
|
HTM_DIV_End ();
|
2019-09-14 12:59:34 +02:00
|
|
|
|
}
|
2019-09-29 22:38:32 +02:00
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**************** Access to variable used to pass parameter ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-12-08 23:19:16 +01:00
|
|
|
|
void Mch_SetCurrentMchCod (long MchCod)
|
2019-09-29 22:38:32 +02:00
|
|
|
|
{
|
|
|
|
|
Mch_CurrentMchCod = MchCod;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-08 23:19:16 +01:00
|
|
|
|
static long Mch_GetCurrentMchCod (void)
|
2019-09-29 22:38:32 +02:00
|
|
|
|
{
|
|
|
|
|
return Mch_CurrentMchCod;
|
|
|
|
|
}
|