{
if ( !active_minigame )
return;
+
active_minigame.minigame_event(active_minigame,"deactivate");
entity e = world;
while( (e = findentity(e, owner, active_minigame)) )
if ( minigame_ent )
minigame_ent.minigame_event(minigame_ent,"network_receive",self,sf);
-
+
if ( sf & MINIG_SF_CREATE )
{
dprint("CL Reading entity: ",ftos(num_for_edict(self)),
if ( take_until > strlen(s) )
take_until = strlen(s);
-
+
for ( int i = 0; i < take_until; i++ )
if ( substring(s,i,1) == "\n" )
{
HUD_Notify_Push(sprintf("minigames/%s/icon_notif",active_minigame.descriptor.netname),
_("It's your turn"), "");
}
-}
\ No newline at end of file
+}
entity HUD_MinigameMenu_last_entry;
// Minigame menu options: insert entry after the given location
-void HUD_MinigameMenu_InsertEntry(entity entry, entity prev)
+void HUD_MinigameMenu_InsertEntry(entity newentry, entity prev)
{
if ( !HUD_MinigameMenu_entries )
{
- HUD_MinigameMenu_entries = entry;
- HUD_MinigameMenu_last_entry = entry;
+ HUD_MinigameMenu_entries = newentry;
+ HUD_MinigameMenu_last_entry = newentry;
return;
}
- entry.list_prev = prev;
- entry.list_next = prev.list_next;
+ newentry.list_prev = prev;
+ newentry.list_next = prev.list_next;
if ( prev.list_next )
- prev.list_next.list_prev = entry;
+ prev.list_next.list_prev = newentry;
else
- HUD_MinigameMenu_last_entry = entry;
- prev.list_next = entry;
+ HUD_MinigameMenu_last_entry = newentry;
+ prev.list_next = newentry;
}
HUD_MinigameMenu_DrawEntry(panel_pos,_("Minigames"),hud_fontsize*2,'0.25 0.47 0.72');
panel_pos_y += hud_fontsize_y*2;
-
+
vector color;
vector offset;
float itemh;
#include "nmm.qc"
#include "ttt.qc"
+#include "c4.qc"
#include "pong.qc"
+#include "qto.qc"
+#include "ps.qc"
+#include "pp.qc"
/**
* Registration:
#define REGISTERED_MINIGAMES \
MINIGAME(nmm, "Nine Men's Morris") \
MINIGAME(ttt, "Tic Tac Toe") \
- MINIGAME(pong, "Pong") \
+ MINIGAME(pong,"Pong") \
+ MINIGAME(c4, "Connect Four") \
+ MINIGAME(qto, "Quinto") \
+ MINIGAME(ps, "Peg Solitaire") \
+ MINIGAME(pp, "Push-Pull") \
/*empty line*/
/**
--- /dev/null
+const float C4_TURN_PLACE = 0x0100; // player has to place a piece on the board
+const float C4_TURN_WIN = 0x0200; // player has won
+const float C4_TURN_DRAW = 0x0400; // no moves are possible
+const float C4_TURN_TYPE = 0x0f00; // turn type mask
+
+const float C4_TURN_TEAM1 = 0x0001;
+const float C4_TURN_TEAM2 = 0x0002;
+const float C4_TURN_TEAM = 0x000f; // turn team mask
+
+const int C4_LET_CNT = 7;
+const int C4_NUM_CNT = 6;
+const int C4_WIN_CNT = 4;
+
+const int C4_MAX_TILES = 42;
+
+const int C4_TILE_SIZE = 8;
+
+const int C4_TEAMS = 2;
+
+.int c4_npieces; // (minigame) number of pieces on the board (simplifies checking a draw)
+.int c4_nexteam; // (minigame) next team (used to change the starting team on following matches)
+
+// find connect 4 piece given its tile name
+entity c4_find_piece(entity minig, string tile)
+{
+ entity e = world;
+ while ( ( e = findentity(e,owner,minig) ) )
+ if ( e.classname == "minigame_board_piece" && e.netname == tile )
+ return e;
+ return world;
+}
+
+// Checks if the given piece completes a row
+bool c4_winning_piece(entity piece)
+{
+ int number = minigame_tile_number(piece.netname);
+ int letter = minigame_tile_letter(piece.netname);
+
+ int i;
+ entity top = piece;
+ entity left = piece;
+ entity topleft = piece;
+ entity botleft = piece;
+ for(i = number; i < C4_NUM_CNT; ++i)
+ {
+ entity p = c4_find_piece(piece.owner,minigame_tile_buildname(letter, i));
+ if(p.team == piece.team)
+ top = p;
+ else break;
+ }
+
+ for(i = letter; i >= 0; --i)
+ {
+ entity p = c4_find_piece(piece.owner,minigame_tile_buildname(i, number));
+ if(p.team == piece.team)
+ left = p;
+ else break;
+ }
+
+ int j;
+ for(i = letter, j = number; i >= 0, j >= 0; --i, --j)
+ {
+ entity p = c4_find_piece(piece.owner,minigame_tile_buildname(i, j));
+ if(p.team == piece.team)
+ botleft = p;
+ else break;
+ }
+ for(i = letter, j = number; i >= 0, j < C4_NUM_CNT; --i, ++j)
+ {
+ entity p = c4_find_piece(piece.owner,minigame_tile_buildname(i, j));
+ if(p.team == piece.team)
+ topleft = p;
+ else break;
+ }
+
+ // down
+ int found = 0;
+ for(i = minigame_tile_number(top.netname); i >= 0; --i)
+ {
+ if(c4_find_piece(piece.owner,minigame_tile_buildname(letter, i)).team == piece.team)
+ ++found;
+ else break;
+ }
+
+ if(found >= C4_WIN_CNT)
+ return true;
+
+ // right
+ found = 0;
+ for(i = minigame_tile_letter(left.netname); i < C4_LET_CNT; ++i)
+ {
+ if(c4_find_piece(piece.owner,minigame_tile_buildname(i, number)).team == piece.team)
+ ++found;
+ else break;
+ }
+
+ if(found >= C4_WIN_CNT)
+ return true;
+
+ // diagright down
+ found = 0;
+ for(i = minigame_tile_letter(topleft.netname), j = minigame_tile_number(topleft.netname); i < C4_LET_CNT, j >= 0; ++i, --j)
+ {
+ if(c4_find_piece(piece.owner,minigame_tile_buildname(i, j)).team == piece.team)
+ ++found;
+ else break;
+ }
+
+ if(found >= C4_WIN_CNT)
+ return true;
+
+ // diagright up
+ found = 0;
+ for(i = minigame_tile_letter(botleft.netname), j = minigame_tile_number(botleft.netname); i < C4_LET_CNT, j < C4_NUM_CNT; ++i, ++j)
+ {
+ if(c4_find_piece(piece.owner,minigame_tile_buildname(i, j)).team == piece.team)
+ ++found;
+ else break;
+ }
+
+ if(found >= C4_WIN_CNT)
+ return true;
+
+ return false;
+}
+
+// check if the tile name is valid (6x7 grid)
+bool c4_valid_tile(string tile)
+{
+ if ( !tile )
+ return false;
+ float number = minigame_tile_number(tile);
+ float letter = minigame_tile_letter(tile);
+ return 0 <= number && number < C4_NUM_CNT && 0 <= letter && letter < C4_LET_CNT;
+}
+
+string c4_get_lowest_tile(entity minigame, string s)
+{
+ int i;
+ int end = 0;
+ for(i = C4_NUM_CNT; i >= 0; --i)
+ {
+ if(!c4_find_piece(minigame,minigame_tile_buildname(minigame_tile_letter(s), i)))
+ if(c4_find_piece(minigame,minigame_tile_buildname(minigame_tile_letter(s), i - 1)))
+ {
+ end = i;
+ break;
+ }
+ }
+ return minigame_tile_buildname(minigame_tile_letter(s), end);
+}
+
+// make a move
+void c4_move(entity minigame, entity player, string pos )
+{
+ pos = c4_get_lowest_tile(minigame, pos);
+
+ if ( minigame.minigame_flags & C4_TURN_PLACE )
+ if ( pos && player.team == (minigame.minigame_flags & C4_TURN_TEAM) )
+ {
+ if ( c4_valid_tile(pos) )
+ if ( !c4_find_piece(minigame,pos) )
+ {
+ entity piece = msle_spawn(minigame,"minigame_board_piece");
+ piece.team = player.team;
+ piece.netname = strzone(pos);
+ minigame_server_sendflags(piece,MINIG_SF_ALL);
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ minigame.c4_npieces++;
+ minigame.c4_nexteam = minigame_next_team(player.team,C4_TEAMS);
+ if ( c4_winning_piece(piece) )
+ {
+ minigame.minigame_flags = C4_TURN_WIN | player.team;
+ }
+ else if ( minigame.c4_npieces >= C4_MAX_TILES )
+ minigame.minigame_flags = C4_TURN_DRAW;
+ else
+ minigame.minigame_flags = C4_TURN_PLACE | minigame.c4_nexteam;
+ }
+ }
+}
+
+#ifdef SVQC
+
+
+// required function, handle server side events
+int c4_server_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "start":
+ {
+ minigame.minigame_flags = (C4_TURN_PLACE | C4_TURN_TEAM1);
+ return true;
+ }
+ case "end":
+ {
+ entity e = world;
+ while( (e = findentity(e, owner, minigame)) )
+ if(e.classname == "minigame_board_piece")
+ {
+ if(e.netname) { strunzone(e.netname); }
+ remove(e);
+ }
+ return false;
+ }
+ case "join":
+ {
+ int pl_num = minigame_count_players(minigame);
+
+ // Don't allow more than 2 players
+ if(pl_num >= C4_TEAMS) { return false; }
+
+ // Get the right team
+ if(minigame.minigame_players)
+ return minigame_next_team(minigame.minigame_players.team, C4_TEAMS);
+
+ // Team 1 by default
+ return 1;
+ }
+ case "cmd":
+ {
+ switch(argv(0))
+ {
+ case "move":
+ c4_move(minigame, ...(0,entity), ...(1,int) == 2 ? argv(1) : string_null );
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+#elif defined(CSQC)
+
+string c4_curr_pos; // identifier of the tile under the mouse
+vector c4_boardpos; // HUD board position
+vector c4_boardsize;// HUD board size
+.int c4_checkwin; // Used to optimize checks to display a win
+
+// Required function, draw the game board
+void c4_hud_board(vector pos, vector mySize)
+{
+ minigame_hud_fitsqare(pos, mySize);
+ c4_boardpos = pos;
+ c4_boardsize = mySize;
+
+ minigame_hud_simpleboard(pos,mySize,minigame_texture("c4/board_under"));
+
+ drawpic(pos, minigame_texture("c4/board_over"), mySize, '1 1 1', 1, 0);
+
+ vector tile_size = minigame_hud_denormalize_size('1 1 0' / C4_TILE_SIZE,pos,mySize);
+ vector tile_pos;
+
+ if ( (active_minigame.minigame_flags & C4_TURN_TEAM) == minigame_self.team )
+ if ( c4_valid_tile(c4_curr_pos) )
+ {
+ tile_pos = minigame_tile_pos(c4_curr_pos,C4_NUM_CNT,C4_LET_CNT);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture(strcat("c4/piece",ftos(minigame_self.team))),
+ tile_size, '1 1 1', panel_fg_alpha/2, DRAWFLAG_NORMAL );
+ }
+
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_board_piece" )
+ {
+ tile_pos = minigame_tile_pos(e.netname,C4_NUM_CNT,C4_LET_CNT);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+
+ if ( active_minigame.minigame_flags & C4_TURN_WIN )
+ if ( !e.c4_checkwin )
+ e.c4_checkwin = c4_winning_piece(e) ? 1 : -1;
+
+ float icon_color = 1;
+ if ( e.c4_checkwin == -1 )
+ icon_color = 0.4;
+ else if ( e.c4_checkwin == 1 )
+ {
+ icon_color = 2;
+ minigame_drawpic_centered( tile_pos, minigame_texture("c4/winglow"),
+ tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_ADDITIVE );
+ }
+
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture(strcat("c4/piece",ftos(e.team))),
+ tile_size, '1 1 1'*icon_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+ }
+ }
+
+ if ( active_minigame.minigame_flags & C4_TURN_WIN )
+ {
+ vector winfs = hud_fontsize*2;
+ string playername = "";
+ FOREACH_MINIGAME_ENTITY(e)
+ if ( e.classname == "minigame_player" &&
+ e.team == (active_minigame.minigame_flags & C4_TURN_TEAM) )
+ playername = GetPlayerName(e.minigame_playerslot-1);
+
+ vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
+ vector win_sz;
+ win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
+ sprintf("%s^7 won the game!",playername),
+ winfs, 0, DRAWFLAG_NORMAL, 0.5);
+
+ drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
+
+ minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
+ sprintf("%s^7 won the game!",playername),
+ winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
+ }
+}
+
+
+// Required function, draw the game status panel
+void c4_hud_status(vector pos, vector mySize)
+{
+ HUD_Panel_DrawBg(1);
+ vector ts;
+ ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
+ hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
+
+ pos_y += ts_y;
+ mySize_y -= ts_y;
+
+ vector player_fontsize = hud_fontsize * 1.75;
+ ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
+ ts_x = mySize_x;
+ vector mypos;
+ vector tile_size = '48 48 0';
+
+ mypos = pos;
+ if ( (active_minigame.minigame_flags&C4_TURN_TEAM) == 2 )
+ mypos_y += player_fontsize_y + ts_y;
+ drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
+ mypos_y += player_fontsize_y;
+ drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
+
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_player" )
+ {
+ mypos = pos;
+ if ( e.team == 2 )
+ mypos_y += player_fontsize_y + ts_y;
+ minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
+ GetPlayerName(e.minigame_playerslot-1),
+ player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ mypos_y += player_fontsize_y;
+ drawpic( mypos,
+ minigame_texture(strcat("c4/piece",ftos(e.team))),
+ tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
+
+ mypos_x += tile_size_x;
+ }
+ }
+}
+
+// Turn a set of flags into a help message
+string c4_turn_to_string(int turnflags)
+{
+ if ( turnflags & C4_TURN_DRAW )
+ return _("Draw");
+
+ if ( turnflags & C4_TURN_WIN )
+ {
+ if ( (turnflags&C4_TURN_TEAM) != minigame_self.team )
+ return _("You lost the game!");
+ return _("You win!");
+ }
+
+ if ( (turnflags & C4_TURN_TEAM) != minigame_self.team )
+ return _("Wait for your opponent to make their move");
+
+ if ( turnflags & C4_TURN_PLACE )
+ return _("Click on the game board to place your piece");
+
+ return "";
+}
+
+// Make the correct move
+void c4_make_move(entity minigame)
+{
+ if ( minigame.minigame_flags == (C4_TURN_PLACE|minigame_self.team) )
+ {
+ minigame_cmd("move ",c4_curr_pos);
+ }
+}
+
+void c4_set_curr_pos(string s)
+{
+ if ( c4_curr_pos )
+ strunzone(c4_curr_pos);
+ if ( s )
+ s = strzone(s);
+ c4_curr_pos = s;
+}
+
+// Required function, handle client events
+int c4_client_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "activate":
+ {
+ c4_set_curr_pos("");
+ minigame.message = c4_turn_to_string(minigame.minigame_flags);
+ return false;
+ }
+ case "key_pressed":
+ {
+ if((minigame.minigame_flags & C4_TURN_TEAM) == minigame_self.team)
+ {
+ switch ( ...(0,int) )
+ {
+ case K_RIGHTARROW:
+ case K_KP_RIGHTARROW:
+ if ( ! c4_curr_pos )
+ c4_set_curr_pos(c4_get_lowest_tile(minigame, "a3"));
+ else
+ c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_relative_tile(c4_curr_pos,1,0,C4_NUM_CNT,C4_LET_CNT)));
+ return true;
+ case K_LEFTARROW:
+ case K_KP_LEFTARROW:
+ if ( ! c4_curr_pos )
+ c4_set_curr_pos(c4_get_lowest_tile(minigame, "c3"));
+ else
+ c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_relative_tile(c4_curr_pos,-1,0,C4_NUM_CNT,C4_LET_CNT)));
+ return true;
+ /*case K_UPARROW:
+ case K_KP_UPARROW:
+ if ( ! c4_curr_pos )
+ c4_set_curr_pos("a1");
+ else
+ c4_set_curr_pos(minigame_relative_tile(c4_curr_pos,0,1,6,7));
+ return true;
+ case K_DOWNARROW:
+ case K_KP_DOWNARROW:
+ if ( ! c4_curr_pos )
+ c4_set_curr_pos("a3");
+ else
+ c4_set_curr_pos(minigame_relative_tile(c4_curr_pos,0,-1,6,7));
+ return true;*/
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_SPACE:
+ c4_make_move(minigame);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ case "mouse_pressed":
+ {
+ if(...(0,int) == K_MOUSE1)
+ {
+ c4_make_move(minigame);
+ return true;
+ }
+
+ return false;
+ }
+ case "mouse_moved":
+ {
+ vector mouse_pos = minigame_hud_normalize(mousepos,c4_boardpos,c4_boardsize);
+ if ( minigame.minigame_flags == (C4_TURN_PLACE|minigame_self.team) )
+ {
+ c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_tile_name(mouse_pos,C4_NUM_CNT,C4_LET_CNT)));
+ }
+ if ( ! c4_valid_tile(c4_curr_pos) )
+ c4_set_curr_pos("");
+
+ return true;
+ }
+ case "network_receive":
+ {
+ entity sent = ...(0,entity);
+ int sf = ...(1,int);
+ if ( sent.classname == "minigame" )
+ {
+ if ( sf & MINIG_SF_UPDATE )
+ {
+ sent.message = c4_turn_to_string(sent.minigame_flags);
+ if ( sent.minigame_flags & minigame_self.team )
+ minigame_prompt();
+ }
+ }
+
+ return false;
+ }
+ }
+
+ return false;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+const int PP_TURN_PLACE = 0x0100; // player has to place a piece on the board
+const int PP_TURN_WIN = 0x0200; // player has won
+const int PP_TURN_DRAW = 0x0400; // players have equal scores
+const int PP_TURN_NEXT = 0x0800; // a player wants to start a new match
+const int PP_TURN_TYPE = 0x0f00; // turn type mask
+
+const int PP_TURN_TEAM1 = 0x0001;
+const int PP_TURN_TEAM2 = 0x0002;
+const int PP_TURN_TEAM = 0x000f; // turn team mask
+
+const int PP_BLOCKED_TEAM = 5; // there won't ever be a 5th team, so we can abuse this
+
+.int pp_team1_score;
+.int pp_team2_score;
+
+.int pp_nexteam;
+
+.entity pp_curr_piece; // identifier for the current target piece
+
+// find tic tac toe piece given its tile name
+entity pp_find_piece(entity minig, string tile)
+{
+ entity e = world;
+ while ( ( e = findentity(e,owner,minig) ) )
+ if ( e.classname == "minigame_board_piece" && e.netname == tile )
+ return e;
+ return world;
+}
+
+// check if the tile name is valid (3x3 grid)
+bool pp_valid_tile(string tile)
+{
+ if ( !tile )
+ return 0;
+ int number = minigame_tile_number(tile);
+ int letter = minigame_tile_letter(tile);
+ return 0 <= number && number < 7 && 0 <= letter && letter < 7;
+}
+
+// Checks if the given piece completes a row
+bool pp_winning_piece(entity piece)
+{
+ int number = minigame_tile_number(piece.netname);
+ int letter = minigame_tile_letter(piece.netname);
+
+ // here goes
+ if(!pp_valid_tile(minigame_tile_buildname(letter-1,number)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter-1,number)).team == 5)
+ if(!pp_valid_tile(minigame_tile_buildname(letter+1,number)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter+1,number)).team == 5)
+ if(!pp_valid_tile(minigame_tile_buildname(letter,number-1)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter,number-1)).team == 5)
+ if(!pp_valid_tile(minigame_tile_buildname(letter,number+1)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter,number+1)).team == 5)
+ if(!pp_valid_tile(minigame_tile_buildname(letter+1,number+1)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter+1,number+1)).team == 5)
+ if(!pp_valid_tile(minigame_tile_buildname(letter-1,number-1)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter-1,number-1)).team == 5)
+ if(!pp_valid_tile(minigame_tile_buildname(letter+1,number-1)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter+1,number-1)).team == 5)
+ if(!pp_valid_tile(minigame_tile_buildname(letter-1,number+1)) || pp_find_piece(piece.owner,minigame_tile_buildname(letter-1,number+1)).team == 5)
+ return true;
+
+ return false;
+}
+
+bool pp_valid_move(entity minigame, string pos)
+{
+ if(!pp_valid_tile(pos))
+ return false;
+ if(pp_find_piece(minigame,pos).team == 5)
+ return false;
+
+ entity current = minigame.pp_curr_piece;
+ if(!current)
+ return true; // no current piece? allow the move anywhere
+
+ int number = minigame_tile_number(pos);
+ int letter = minigame_tile_letter(pos);
+
+ if( (pp_find_piece(minigame,minigame_tile_buildname(letter-1,number)) == current)
+ || (pp_find_piece(minigame,minigame_tile_buildname(letter+1,number)) == current)
+ || (pp_find_piece(minigame,minigame_tile_buildname(letter,number-1)) == current)
+ || (pp_find_piece(minigame,minigame_tile_buildname(letter,number+1)) == current)
+ || (pp_find_piece(minigame,minigame_tile_buildname(letter+1,number+1)) == current)
+ || (pp_find_piece(minigame,minigame_tile_buildname(letter-1,number-1)) == current)
+ || (pp_find_piece(minigame,minigame_tile_buildname(letter+1,number-1)) == current)
+ || (pp_find_piece(minigame,minigame_tile_buildname(letter-1,number+1)) == current)
+ ) { return true; }
+
+ return false;
+}
+
+// make a move
+void pp_move(entity minigame, entity player, string pos )
+{
+ if ( minigame.minigame_flags & PP_TURN_PLACE )
+ if ( pos && player.team == (minigame.minigame_flags & PP_TURN_TEAM) )
+ {
+ if ( pp_valid_move(minigame,pos))
+ {
+ entity existing = pp_find_piece(minigame,pos);
+
+ if(existing && existing.team != 5)
+ {
+ if(existing.team == 1)
+ minigame.pp_team1_score++;
+ if(existing.team == 2)
+ minigame.pp_team2_score++;
+ }
+
+ if(minigame.pp_curr_piece)
+ {
+ minigame.pp_curr_piece.cnt = 0;
+ minigame.pp_curr_piece.team = 5;
+ minigame_server_sendflags(minigame.pp_curr_piece,MINIG_SF_ALL);
+ }
+
+ if(existing)
+ {
+ if(existing.netname) { strunzone(existing.netname); }
+ remove(existing);
+ }
+
+ entity piece = msle_spawn(minigame,"minigame_board_piece");
+ piece.cnt = 1;
+ piece.team = player.team; // temporary
+ piece.netname = strzone(pos);
+ minigame_server_sendflags(piece,MINIG_SF_ALL);
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ minigame.pp_nexteam = minigame_next_team(player.team,2);
+ minigame.pp_curr_piece = piece;
+ if ( pp_winning_piece(piece) )
+ {
+ if(minigame.pp_team1_score == minigame.pp_team2_score)
+ minigame.minigame_flags = PP_TURN_DRAW;
+ else
+ minigame.minigame_flags = PP_TURN_WIN | ((minigame.pp_team1_score > minigame.pp_team2_score) ? 1 : 2);
+ }
+ else
+ minigame.minigame_flags = PP_TURN_PLACE | minigame.pp_nexteam;
+ }
+ }
+}
+
+void pp_setup_pieces(entity minigame)
+{
+ int i, t; // letter, number
+ for(i = 0; i < 7; ++i)
+ for(t = 0; t < 7; ++t)
+ {
+ bool t2_true = ((i == 0 || i == 6) && t > 0 && t < 6);
+ bool t1_true = (i > 0 && i < 6 && (t == 0 || t == 6));
+
+ if(t1_true || t2_true)
+ {
+ entity piece = msle_spawn(minigame,"minigame_board_piece");
+ piece.team = ((t1_true) ? 1 : 2);
+ piece.netname = strzone(minigame_tile_buildname(i,t));
+ minigame_server_sendflags(piece,MINIG_SF_ALL);
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ }
+ }
+
+ minigame.pp_curr_piece = world;
+}
+
+// request a new match
+void pp_next_match(entity minigame, entity player)
+{
+#ifdef SVQC
+ // on multiplayer matches, wait for both players to agree
+ if ( minigame.minigame_flags & (PP_TURN_WIN|PP_TURN_DRAW) )
+ {
+ minigame.minigame_flags = PP_TURN_NEXT | player.team;
+ minigame.SendFlags |= MINIG_SF_UPDATE;
+ }
+ else if ( (minigame.minigame_flags & PP_TURN_NEXT) &&
+ !( minigame.minigame_flags & player.team ) )
+#endif
+ {
+ minigame.minigame_flags = PP_TURN_PLACE | minigame.pp_nexteam;
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ entity e = world;
+ while ( ( e = findentity(e,owner,minigame) ) )
+ if ( e.classname == "minigame_board_piece" )
+ remove(e);
+ minigame.pp_team1_score = 0;
+ minigame.pp_team2_score = 0;
+
+ pp_setup_pieces(minigame);
+ }
+}
+
+#ifdef SVQC
+
+
+// required function, handle server side events
+int pp_server_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "start":
+ {
+ minigame.minigame_flags = (PP_TURN_PLACE | PP_TURN_TEAM1);
+ pp_setup_pieces(minigame);
+ return true;
+ }
+ case "end":
+ {
+ entity e = world;
+ while( (e = findentity(e, owner, minigame)) )
+ if(e.classname == "minigame_board_piece")
+ {
+ if(e.netname) { strunzone(e.netname); }
+ remove(e);
+ }
+ return false;
+ }
+ case "join":
+ {
+ int pl_num = minigame_count_players(minigame);
+
+ // Don't allow more than 2 players
+ if(pl_num >= 2) { return false; }
+
+ // Get the right team
+ if(minigame.minigame_players)
+ return minigame_next_team(minigame.minigame_players.team, 2);
+
+ // Team 1 by default
+ return 1;
+ }
+ case "cmd":
+ {
+ switch(argv(0))
+ {
+ case "move":
+ pp_move(minigame, ...(0,entity), ...(1,int) == 2 ? argv(1) : string_null );
+ return true;
+ case "next":
+ pp_next_match(minigame,...(0,entity));
+ return true;
+ }
+
+ return false;
+ }
+ case "network_send":
+ {
+ entity sent = ...(0,entity);
+ int sf = ...(1,int);
+ if ( sent.classname == "minigame" && (sf & MINIG_SF_UPDATE ) )
+ {
+ WriteByte(MSG_ENTITY,sent.pp_team1_score);
+ WriteByte(MSG_ENTITY,sent.pp_team2_score);
+ }
+ else if(sent.classname == "minigame_board_piece")
+ WriteByte(MSG_ENTITY,sent.cnt);
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+#elif defined(CSQC)
+
+string pp_curr_pos; // identifier of the tile under the mouse
+vector pp_boardpos; // HUD board position
+vector pp_boardsize;// HUD board size
+.int pp_checkwin; // Used to optimize checks to display a win
+
+// Required function, draw the game board
+void pp_hud_board(vector pos, vector mySize)
+{
+ minigame_hud_fitsqare(pos, mySize);
+ pp_boardpos = pos;
+ pp_boardsize = mySize;
+
+ minigame_hud_simpleboard(pos,mySize,minigame_texture("pp/board"));
+
+ vector tile_size = minigame_hud_denormalize_size('1 1 0'/7,pos,mySize);
+ vector tile_pos;
+
+ active_minigame.pp_curr_piece = world;
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ if(e.classname == "minigame_board_piece")
+ if(e.cnt)
+ {
+ active_minigame.pp_curr_piece = e;
+ break;
+ }
+
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_board_piece" )
+ {
+ tile_pos = minigame_tile_pos(e.netname,7,7);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+
+ vector tile_color = '1 1 1';
+ switch(e.team)
+ {
+ case 1: tile_color = '1 0.3 0.3'; break;
+ case 2: tile_color = '0.3 0.3 1'; break;
+ // 3, 4 coming later?
+ }
+
+ string tile_name = strcat("pp/piece",ftos(e.team));
+ if(e.team == 5) { tile_name = "pp/piece_taken"; }
+
+ if(e == active_minigame.pp_curr_piece)
+ {
+ tile_name = "pp/piece_current";
+
+ // draw the splat too
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture("pp/piece_taken"),
+ tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
+ }
+
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture(tile_name),
+ tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+ }
+ }
+
+ if ( (active_minigame.minigame_flags & PP_TURN_TEAM) == minigame_self.team )
+ if ( pp_valid_move(active_minigame, pp_curr_pos) )
+ {
+ tile_pos = minigame_tile_pos(pp_curr_pos,7,7);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture("pp/piece_current"),
+ tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
+ }
+ else if(pp_valid_tile(pp_curr_pos))
+ {
+ tile_pos = minigame_tile_pos(pp_curr_pos,7,7);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture("pp/piece_selected"),
+ tile_size, '1 1 1', panel_fg_alpha / 2, DRAWFLAG_NORMAL );
+ }
+
+ if ( active_minigame.minigame_flags & PP_TURN_WIN )
+ {
+ vector winfs = hud_fontsize*2;
+ string playername = "";
+ FOREACH_MINIGAME_ENTITY(e)
+ if ( e.classname == "minigame_player" &&
+ e.team == (active_minigame.minigame_flags & PP_TURN_TEAM) )
+ playername = GetPlayerName(e.minigame_playerslot-1);
+
+ vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
+ vector win_sz;
+ win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
+ sprintf("%s^7 won the game!",playername),
+ winfs, 0, DRAWFLAG_NORMAL, 0.5);
+
+ drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
+
+ minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
+ sprintf("%s^7 won the game!",playername),
+ winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
+ }
+}
+
+
+// Required function, draw the game status panel
+void pp_hud_status(vector pos, vector mySize)
+{
+ HUD_Panel_DrawBg(1);
+ vector ts;
+ ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
+ hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
+
+ pos_y += ts_y;
+ mySize_y -= ts_y;
+
+ vector player_fontsize = hud_fontsize * 1.75;
+ ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
+ ts_x = mySize_x;
+ vector mypos;
+ vector tile_size = '48 48 0';
+
+ mypos = pos;
+ if ( (active_minigame.minigame_flags&PP_TURN_TEAM) == 2 )
+ mypos_y += player_fontsize_y + ts_y;
+ drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
+ mypos_y += player_fontsize_y;
+ drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
+
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_player" )
+ {
+ vector tile_color = '1 1 1';
+ switch(e.team)
+ {
+ case 1: tile_color = '1 0.3 0.3'; break;
+ case 2: tile_color = '0.3 0.3 1'; break;
+ // 3, 4 coming later?
+ }
+
+ mypos = pos;
+ if ( e.team == 2 )
+ mypos_y += player_fontsize_y + ts_y;
+ minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
+ GetPlayerName(e.minigame_playerslot-1),
+ player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ mypos_y += player_fontsize_y;
+ drawpic( mypos,
+ minigame_texture(strcat("pp/piece",ftos(e.team))),
+ tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+
+ mypos_x += tile_size_x;
+ int myscore = 0;
+ if(e.team == 1) { myscore = active_minigame.pp_team1_score; }
+ if(e.team == 2) { myscore = active_minigame.pp_team2_score; }
+
+ drawstring(mypos,ftos(myscore),tile_size,
+ '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ }
+}
+
+// Turn a set of flags into a help message
+string pp_turn_to_string(int turnflags)
+{
+ if ( turnflags & PP_TURN_DRAW )
+ return _("Draw");
+
+ if ( turnflags & PP_TURN_WIN )
+ {
+ if ( (turnflags&PP_TURN_TEAM) != minigame_self.team )
+ return _("You lost the game!\nSelect \"^1Next Match^7\" on the menu for a rematch!");
+ return _("You win!\nSelect \"^1Next Match^7\" on the menu to start a new match!");
+ }
+
+ if ( turnflags & PP_TURN_NEXT )
+ {
+ if ( (turnflags&PP_TURN_TEAM) != minigame_self.team )
+ return _("Select \"^1Next Match^7\" on the menu to start a new match!");
+ return _("Wait for your opponent to confirm the rematch");
+ }
+
+ if ( (turnflags & PP_TURN_TEAM) != minigame_self.team )
+ return _("Wait for your opponent to make their move");
+
+ if ( turnflags & PP_TURN_PLACE )
+ return _("Click on the game board to place your piece");
+
+ return "";
+}
+
+// Make the correct move
+void pp_make_move(entity minigame)
+{
+ if ( minigame.minigame_flags == (PP_TURN_PLACE|minigame_self.team) )
+ {
+ minigame_cmd("move ",pp_curr_pos);
+ }
+}
+
+void pp_set_curr_pos(string s)
+{
+ if ( pp_curr_pos )
+ strunzone(pp_curr_pos);
+ if ( s )
+ s = strzone(s);
+ pp_curr_pos = s;
+}
+
+// Required function, handle client events
+int pp_client_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "activate":
+ {
+ pp_set_curr_pos("");
+ minigame.message = pp_turn_to_string(minigame.minigame_flags);
+ return false;
+ }
+ case "key_pressed":
+ {
+ if((minigame.minigame_flags & PP_TURN_TEAM) == minigame_self.team)
+ {
+ switch ( ...(0,int) )
+ {
+ case K_RIGHTARROW:
+ case K_KP_RIGHTARROW:
+ if ( ! pp_curr_pos )
+ pp_set_curr_pos("a3");
+ else
+ pp_set_curr_pos(minigame_relative_tile(pp_curr_pos,1,0,7,7));
+ return true;
+ case K_LEFTARROW:
+ case K_KP_LEFTARROW:
+ if ( ! pp_curr_pos )
+ pp_set_curr_pos("c3");
+ else
+ pp_set_curr_pos(minigame_relative_tile(pp_curr_pos,-1,0,7,7));
+ return true;
+ case K_UPARROW:
+ case K_KP_UPARROW:
+ if ( ! pp_curr_pos )
+ pp_set_curr_pos("a1");
+ else
+ pp_set_curr_pos(minigame_relative_tile(pp_curr_pos,0,1,7,7));
+ return true;
+ case K_DOWNARROW:
+ case K_KP_DOWNARROW:
+ if ( ! pp_curr_pos )
+ pp_set_curr_pos("a3");
+ else
+ pp_set_curr_pos(minigame_relative_tile(pp_curr_pos,0,-1,7,7));
+ return true;
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_SPACE:
+ pp_make_move(minigame);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ case "mouse_pressed":
+ {
+ if(...(0,int) == K_MOUSE1)
+ {
+ pp_make_move(minigame);
+ return true;
+ }
+
+ return false;
+ }
+ case "mouse_moved":
+ {
+ vector mouse_pos = minigame_hud_normalize(mousepos,pp_boardpos,pp_boardsize);
+ if ( minigame.minigame_flags == (PP_TURN_PLACE|minigame_self.team) )
+ pp_set_curr_pos(minigame_tile_name(mouse_pos,7,7));
+ if ( ! pp_valid_tile(pp_curr_pos) )
+ pp_set_curr_pos("");
+
+ return true;
+ }
+ case "network_receive":
+ {
+ entity sent = ...(0,entity);
+ int sf = ...(1,int);
+ if ( sent.classname == "minigame" )
+ {
+ if ( sf & MINIG_SF_UPDATE )
+ {
+ sent.message = pp_turn_to_string(sent.minigame_flags);
+ if ( sent.minigame_flags & minigame_self.team )
+ minigame_prompt();
+ sent.pp_team1_score = ReadByte();
+ sent.pp_team2_score = ReadByte();
+ }
+ }
+ else if(sent.classname == "minigame_board_piece")
+ {
+ sent.cnt = ReadByte();
+ if(sent.cnt)
+ minigame.pp_curr_piece = sent;
+ }
+
+ return false;
+ }
+ case "menu_show":
+ {
+ HUD_MinigameMenu_CustomEntry(...(0,entity),_("Next Match"),"next");
+ return false;
+ }
+ case "menu_click":
+ {
+ if(...(0,string) == "next")
+ minigame_cmd("next");
+ return false;
+ }
+ }
+
+ return false;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+const float PS_TURN_MOVE = 0x0100; // player has to click on a piece on the board
+const float PS_TURN_WIN = 0x0200; // player has won
+const float PS_TURN_DRAW = 0x0400; // player can make no more moves
+const float PS_TURN_TYPE = 0x0f00; // turn type mask
+
+const int PS_LET_CNT = 7;
+const int PS_NUM_CNT = 7;
+
+const int PS_TILE_SIZE = 8;
+
+// find same game piece given its tile name
+entity ps_find_piece(entity minig, string tile)
+{
+ entity e = world;
+ while ( ( e = findentity(e,owner,minig) ) )
+ if ( e.classname == "minigame_board_piece" && e.netname == tile )
+ return e;
+ return world;
+}
+
+bool ps_draw(entity minigame)
+{
+ int valid = 0;
+ entity e = world;
+ while( ( e = findentity(e,owner,minigame) ) )
+ if( e.classname == "minigame_board_piece" )
+ {
+ ++valid;
+ }
+
+ return ((valid > 0) ? true : false);
+}
+
+bool ps_tile_blacklisted(string tile)
+{
+ int number = minigame_tile_number(tile);
+ int letter = minigame_tile_letter(tile);
+ if(letter < 2)
+ if(number < 2)
+ return true;
+ else if(number > PS_NUM_CNT - 3)
+ return true;
+ if(letter > PS_LET_CNT - 3)
+ if(number < 2)
+ return true;
+ else if(number > PS_NUM_CNT - 3)
+ return true;
+
+ return false;
+}
+
+// check if the tile name is valid (5x5 grid)
+bool ps_valid_tile(string tile)
+{
+ if ( !tile )
+ return false;
+ if(ps_tile_blacklisted(tile))
+ return false;
+ float number = minigame_tile_number(tile);
+ float letter = minigame_tile_letter(tile);
+ return 0 <= number && number < PS_NUM_CNT && 0 <= letter && letter < PS_LET_CNT;
+}
+
+// Checks if the given piece completes a row
+bool ps_winning_piece(entity minigame)
+{
+ //int number = minigame_tile_number(piece.netname);
+ //int letter = minigame_tile_letter(piece.netname);
+
+ entity e = world;
+ while ( ( e = findentity(e,owner,minigame) ) )
+ if ( e.classname == "minigame_board_piece" )
+ {
+ int number = minigame_tile_number(e.netname);
+ int letter = minigame_tile_letter(e.netname);
+ string try = minigame_tile_buildname(letter - 1, number);
+ if(ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter - 2, number);
+ if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
+ return false; // a move is valid, abort!
+ }
+ try = minigame_tile_buildname(letter + 1, number);
+ if(ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter + 2, number);
+ if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
+ return false; // a move is valid, abort!
+ }
+ try = minigame_tile_buildname(letter, number - 1);
+ if(ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter, number - 2);
+ if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
+ return false; // a move is valid, abort!
+ }
+ try = minigame_tile_buildname(letter, number + 1);
+ if(ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter, number + 2);
+ if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
+ return false; // a move is valid, abort!
+ }
+ }
+
+ return true;
+}
+
+void ps_setup_pieces(entity minigame)
+{
+ int i, t;
+ for(i = 0; i < PS_NUM_CNT; ++i)
+ for(t = 0; t < PS_LET_CNT; ++t)
+ {
+ string try = minigame_tile_buildname(i,t);
+ if(!ps_valid_tile(try))
+ continue;
+ if(i == floor(PS_NUM_CNT * 0.5) && t == floor(PS_LET_CNT * 0.5))
+ continue; // middle piece is empty
+ entity piece = msle_spawn(minigame,"minigame_board_piece");
+ piece.team = 1; // init default team?
+ piece.netname = strzone(minigame_tile_buildname(t,i));
+ minigame_server_sendflags(piece,MINIG_SF_ALL);
+ }
+
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+}
+
+bool ps_move_piece(entity minigame, entity piece, string pos, int leti, int numb)
+{
+ if(!piece)
+ return false;
+ if(ps_find_piece(minigame, pos))
+ return false;
+ entity middle = ps_find_piece(minigame, minigame_tile_buildname(leti,numb));
+ if(!middle)
+ return false;
+
+ if(middle.netname) { strunzone(middle.netname); }
+ remove(middle);
+
+ if(piece.netname) { strunzone(piece.netname); }
+ piece.netname = strzone(pos);
+
+ minigame_server_sendflags(piece,MINIG_SF_ALL);
+
+ return true;
+}
+
+// make a move
+void ps_move(entity minigame, entity player, string thepiece, string pos )
+{
+ if ( minigame.minigame_flags & PS_TURN_MOVE )
+ if ( pos )
+ {
+ if ( ps_valid_tile(pos) )
+ if ( !ps_find_piece(minigame, pos) && ps_find_piece(minigame, thepiece) )
+ {
+ entity piece = ps_find_piece(minigame, thepiece);
+ int number = minigame_tile_number(thepiece);
+ int letter = minigame_tile_letter(thepiece);
+ bool done = false;
+ string try;
+
+ try = minigame_tile_buildname(letter-1,number);
+ if(ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter-2,number);
+ if(ps_valid_tile(try) && try == pos)
+ done = ps_move_piece(minigame, piece, pos, letter - 1, number);
+ }
+ try = minigame_tile_buildname(letter+1,number);
+ if(!done && ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter+2,number);
+ if(ps_valid_tile(try) && try == pos)
+ done = ps_move_piece(minigame, piece, pos, letter + 1, number);
+ }
+ try = minigame_tile_buildname(letter,number-1);
+ if(!done && ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter,number-2);
+ if(ps_valid_tile(try) && try == pos)
+ done = ps_move_piece(minigame, piece, pos, letter, number - 1);
+ }
+ try = minigame_tile_buildname(letter,number+1);
+ if(!done && ps_find_piece(minigame,try))
+ {
+ try = minigame_tile_buildname(letter,number+2);
+ if(ps_valid_tile(try) && try == pos)
+ done = ps_move_piece(minigame, piece, pos, letter, number + 1);
+ }
+
+ if(!done)
+ return; // didn't make a move
+
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+
+ if ( ps_winning_piece(minigame) )
+ {
+ if(ps_draw(minigame))
+ minigame.minigame_flags = PS_TURN_DRAW;
+ else
+ minigame.minigame_flags = PS_TURN_WIN;
+ }
+ else
+ minigame.minigame_flags = PS_TURN_MOVE;
+ }
+ }
+}
+
+#ifdef SVQC
+
+
+// required function, handle server side events
+int ps_server_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "start":
+ {
+ ps_setup_pieces(minigame);
+ minigame.minigame_flags = PS_TURN_MOVE;
+ return true;
+ }
+ case "end":
+ {
+ entity e = world;
+ while( (e = findentity(e, owner, minigame)) )
+ if(e.classname == "minigame_board_piece")
+ {
+ if(e.netname) { strunzone(e.netname); }
+ remove(e);
+ }
+ return false;
+ }
+ case "join":
+ {
+ int pl_num = minigame_count_players(minigame);
+
+ // Don't allow more than 1 player
+ if(pl_num >= 1) { return false; }
+
+ // Team 1 by default
+ return 1;
+ }
+ case "cmd":
+ {
+ switch(argv(0))
+ {
+ case "move":
+
+ ps_move(minigame, ...(0,entity), (...(1,int) == 3 ? argv(1) : string_null), (...(1,int) == 3 ? argv(2) : string_null));
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+#elif defined(CSQC)
+
+entity ps_curr_piece; // identifier for the currently selected piece
+string ps_curr_pos; // identifier of the tile under the mouse
+vector ps_boardpos; // HUD board position
+vector ps_boardsize;// HUD board size
+
+// Required function, draw the game board
+void ps_hud_board(vector pos, vector mySize)
+{
+ minigame_hud_fitsqare(pos, mySize);
+ ps_boardpos = pos;
+ ps_boardsize = mySize;
+
+ minigame_hud_simpleboard(pos,mySize,minigame_texture("ps/board"));
+
+ vector tile_size = minigame_hud_denormalize_size('1 1 0' / PS_TILE_SIZE,pos,mySize);
+ vector tile_pos;
+
+ bool valid = ps_valid_tile(ps_curr_pos);
+ bool highlight = false;
+ if(valid)
+ {
+ string try;
+ int number = minigame_tile_number(ps_curr_pos);
+ int letter = minigame_tile_letter(ps_curr_pos);
+ try = minigame_tile_buildname(letter-1,number);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(letter-2,number);
+ if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
+ highlight = true;
+ }
+ try = minigame_tile_buildname(letter+1,number);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(letter+2,number);
+ if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
+ highlight = true;
+ }
+ try = minigame_tile_buildname(letter,number-1);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(letter,number-2);
+ if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
+ highlight = true;
+ }
+ try = minigame_tile_buildname(letter,number+1);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(letter,number+2);
+ if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
+ highlight = true;
+ }
+ }
+ bool draw_pos = false;
+ if(ps_curr_piece && valid && !ps_find_piece(active_minigame, ps_curr_pos))
+ {
+ string try; // sigh
+ int numb = minigame_tile_number(ps_curr_piece.netname);
+ int leti = minigame_tile_letter(ps_curr_piece.netname);
+
+ try = minigame_tile_buildname(leti-1,numb);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(leti-2,numb);
+ if(try == ps_curr_pos)
+ draw_pos = true;
+ }
+ try = minigame_tile_buildname(leti+1,numb);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(leti+2,numb);
+ if(try == ps_curr_pos)
+ draw_pos = true;
+ }
+ try = minigame_tile_buildname(leti,numb-1);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(leti,numb-2);
+ if(try == ps_curr_pos)
+ draw_pos = true;
+ }
+ try = minigame_tile_buildname(leti,numb+1);
+ if(ps_find_piece(active_minigame,try))
+ {
+ try = minigame_tile_buildname(leti,numb+2);
+ if(try == ps_curr_pos)
+ draw_pos = true;
+ }
+ }
+
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_board_piece" )
+ {
+ tile_pos = minigame_tile_pos(e.netname,PS_NUM_CNT,PS_LET_CNT);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+
+ vector tile_color = '1 1 1';
+
+ if(highlight)
+ if(e.netname == ps_curr_pos)
+ if(ps_curr_piece.netname != ps_curr_pos)
+ {
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture("ps/tile_available"),
+ tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+ }
+ if(e == ps_curr_piece)
+ {
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture("ps/tile_selected"),
+ tile_size, tile_color, panel_fg_alpha, DRAWFLAG_ADDITIVE );
+ }
+
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture("ps/piece"),
+ tile_size * 0.8, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+ }
+ }
+
+ if(draw_pos)
+ {
+ tile_pos = minigame_tile_pos(ps_curr_pos,PS_NUM_CNT,PS_LET_CNT);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+
+ minigame_drawpic_centered(tile_pos,
+ minigame_texture("ps/piece"),
+ tile_size * 0.8, '0.5 0.5 0.5', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ if ( ( active_minigame.minigame_flags & PS_TURN_WIN ) || ( active_minigame.minigame_flags & PS_TURN_DRAW ) )
+ {
+ int remaining = 0;
+ FOREACH_MINIGAME_ENTITY(e)
+ if(e.classname == "minigame_board_piece")
+ ++remaining;
+
+ vector winfs = hud_fontsize*2;
+ string remaining_text;
+ if(active_minigame.minigame_flags & PS_TURN_WIN)
+ remaining_text = "All pieces cleared!";
+ else
+ remaining_text = strcat("Remaining pieces: ", ftos(remaining));
+
+ vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
+ vector win_sz;
+ win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
+ sprintf("Game over! %s", remaining_text),
+ winfs, 0, DRAWFLAG_NORMAL, 0.5);
+
+ drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
+
+ minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
+ sprintf("Game over! %s", remaining_text),
+ winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
+ }
+}
+
+
+// Required function, draw the game status panel
+void ps_hud_status(vector pos, vector mySize)
+{
+ HUD_Panel_DrawBg(1);
+ vector ts;
+ ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
+ hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
+
+ pos_y += ts_y;
+ mySize_y -= ts_y;
+
+ vector player_fontsize = hud_fontsize * 1.75;
+ ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
+ ts_x = mySize_x;
+ vector mypos;
+ vector tile_size = '48 48 0';
+
+ mypos = pos;
+ drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
+ mypos_y += player_fontsize_y;
+ drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
+
+ int remaining = 0;
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if(e.classname == "minigame_board_piece")
+ {
+ ++remaining;
+ }
+ }
+
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_player" )
+ {
+ mypos = pos;
+ minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
+ GetPlayerName(e.minigame_playerslot-1),
+ player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ mypos_y += player_fontsize_y;
+ //drawpic( mypos,
+ // minigame_texture("ps/piece"),
+ // tile_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL );
+
+ //mypos_x += tile_size_x;
+
+ drawstring(mypos,sprintf(_("Pieces left: %s"), ftos(remaining)),'28 28 0',
+ '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ }
+}
+
+// Turn a set of flags into a help message
+string ps_turn_to_string(int turnflags)
+{
+ if (turnflags & PS_TURN_DRAW )
+ return _("No more valid moves");
+
+ if ( turnflags & PS_TURN_WIN )
+ return _("Well done, you win!");
+
+ if ( turnflags & PS_TURN_MOVE )
+ return _("Jump a piece over another to capture it");
+
+ return "";
+}
+
+// Make the correct move
+void ps_make_move(entity minigame)
+{
+ if ( minigame.minigame_flags == PS_TURN_MOVE )
+ {
+ entity piece = ps_find_piece(minigame,ps_curr_pos);
+ if(!ps_curr_piece || piece)
+ ps_curr_piece = ps_find_piece(minigame,ps_curr_pos);
+ else
+ {
+ minigame_cmd("move ", ps_curr_piece.netname, " ", ps_curr_pos);
+ ps_curr_piece = world;
+ }
+ }
+}
+
+void ps_set_curr_pos(string s)
+{
+ if ( ps_curr_pos )
+ strunzone(ps_curr_pos);
+ if ( s )
+ s = strzone(s);
+ ps_curr_pos = s;
+}
+
+// Required function, handle client events
+int ps_client_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "activate":
+ {
+ ps_set_curr_pos("");
+ ps_curr_piece = world;
+ minigame.message = ps_turn_to_string(minigame.minigame_flags);
+ return false;
+ }
+ case "key_pressed":
+ {
+ //if((minigame.minigame_flags & PS_TURN_TEAM) == minigame_self.team)
+ {
+ switch ( ...(0,int) )
+ {
+ case K_RIGHTARROW:
+ case K_KP_RIGHTARROW:
+ if ( ! ps_curr_pos )
+ ps_set_curr_pos("a3");
+ else
+ ps_set_curr_pos( minigame_relative_tile(ps_curr_pos,1,0,PS_NUM_CNT,PS_LET_CNT));
+ return true;
+ case K_LEFTARROW:
+ case K_KP_LEFTARROW:
+ if ( ! ps_curr_pos )
+ ps_set_curr_pos("c3");
+ else
+ ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,-1,0,PS_NUM_CNT,PS_LET_CNT));
+ return true;
+ case K_UPARROW:
+ case K_KP_UPARROW:
+ if ( ! ps_curr_pos )
+ ps_set_curr_pos("a1");
+ else
+ ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,0,1,PS_NUM_CNT,PS_LET_CNT));
+ return true;
+ case K_DOWNARROW:
+ case K_KP_DOWNARROW:
+ if ( ! ps_curr_pos )
+ ps_set_curr_pos("a3");
+ else
+ ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,0,-1,PS_NUM_CNT,PS_LET_CNT));
+ return true;
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_SPACE:
+ ps_make_move(minigame);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ case "mouse_pressed":
+ {
+ if(...(0,int) == K_MOUSE1)
+ {
+ ps_make_move(minigame);
+ return true;
+ }
+
+ return false;
+ }
+ case "mouse_moved":
+ {
+ vector mouse_pos = minigame_hud_normalize(mousepos,ps_boardpos,ps_boardsize);
+ if ( minigame.minigame_flags == PS_TURN_MOVE )
+ {
+ ps_set_curr_pos(minigame_tile_name(mouse_pos,PS_NUM_CNT,PS_LET_CNT));
+ }
+ if ( ! ps_valid_tile(ps_curr_pos) )
+ ps_set_curr_pos("");
+
+ return true;
+ }
+ case "network_receive":
+ {
+ entity sent = ...(0,entity);
+ int sf = ...(1,int);
+ if ( sent.classname == "minigame" )
+ {
+ if ( sf & MINIG_SF_UPDATE )
+ {
+ sent.message = ps_turn_to_string(sent.minigame_flags);
+ if ( sent.minigame_flags & minigame_self.team )
+ minigame_prompt();
+ }
+ }
+
+ return false;
+ }
+ }
+
+ return false;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+const float QTO_TURN_MOVE = 0x0100; // player has to click on a piece on the board
+const float QTO_TURN_WIN = 0x0200; // player has won
+const float QTO_TURN_TYPE = 0x0f00; // turn type mask
+
+const int QTO_SF_PLAYERSCORE = MINIG_SF_CUSTOM;
+
+const int QTO_LET_CNT = 5;
+const int QTO_NUM_CNT = 5;
+
+const int QTO_TILE_SIZE = 8;
+
+.int qto_moves;
+
+// find same game piece given its tile name
+entity qto_find_piece(entity minig, string tile)
+{
+ entity e = world;
+ while ( ( e = findentity(e,owner,minig) ) )
+ if ( e.classname == "minigame_board_piece" && e.netname == tile )
+ return e;
+ return world;
+}
+
+// Checks if the given piece completes a row
+bool qto_winning_piece(entity minigame)
+{
+ //int number = minigame_tile_number(piece.netname);
+ //int letter = minigame_tile_letter(piece.netname);
+
+ entity e = world;
+ while ( ( e = findentity(e,owner,minigame) ) )
+ if ( e.classname == "minigame_board_piece" )
+ {
+ if(!e.cnt)
+ return false;
+ }
+
+ return true;
+}
+
+// check if the tile name is valid (5x5 grid)
+bool qto_valid_tile(string tile)
+{
+ if ( !tile )
+ return false;
+ float number = minigame_tile_number(tile);
+ float letter = minigame_tile_letter(tile);
+ return 0 <= number && number < QTO_NUM_CNT && 0 <= letter && letter < QTO_LET_CNT;
+}
+
+void qto_setup_pieces(entity minigame)
+{
+ int i, t;
+ for(i = 0; i < QTO_NUM_CNT; ++i)
+ for(t = 0; t < QTO_LET_CNT; ++t)
+ {
+ entity piece = msle_spawn(minigame,"minigame_board_piece");
+ piece.team = 1; // init default team?
+ piece.cnt = 0; // initialize cnt
+ piece.netname = strzone(minigame_tile_buildname(t,i));
+ minigame_server_sendflags(piece,MINIG_SF_ALL);
+ }
+
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+}
+
+void qto_add_score(entity minigame, int thescore)
+{
+#ifdef SVQC
+ if(!minigame)
+ return;
+ if(minigame.minigame_players)
+ {
+ minigame.minigame_players.qto_moves += thescore;
+ minigame.minigame_players.SendFlags |= QTO_SF_PLAYERSCORE;
+ }
+#endif
+}
+
+// make a move
+void qto_move(entity minigame, entity player, string pos )
+{
+ if ( minigame.minigame_flags & QTO_TURN_MOVE )
+ if ( pos )
+ {
+ if ( qto_valid_tile(pos) )
+ if ( qto_find_piece(minigame, pos) )
+ {
+ entity piece;
+ #define DO_JUNK \
+ if(piece) \
+ { \
+ piece.cnt = (piece.cnt) ? 0 : 1; \
+ minigame_server_sendflags(piece,MINIG_SF_UPDATE); \
+ }
+
+ int number = minigame_tile_number(pos);
+ int letter = minigame_tile_letter(pos);
+ piece = qto_find_piece(minigame, pos);
+ DO_JUNK
+ piece = qto_find_piece(minigame, minigame_tile_buildname(letter-1,number));
+ DO_JUNK
+ piece = qto_find_piece(minigame, minigame_tile_buildname(letter+1,number));
+ DO_JUNK
+ piece = qto_find_piece(minigame, minigame_tile_buildname(letter,number-1));
+ DO_JUNK
+ piece = qto_find_piece(minigame, minigame_tile_buildname(letter,number+1));
+ DO_JUNK
+
+ qto_add_score(minigame,1); // add 1 move score
+
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+
+ if ( qto_winning_piece(minigame) )
+ {
+ minigame.minigame_flags = QTO_TURN_WIN;
+ }
+ else
+ minigame.minigame_flags = QTO_TURN_MOVE;
+ }
+ }
+}
+
+// restart match
+void qto_restart_match(entity minigame, entity player)
+{
+ minigame.minigame_flags = QTO_TURN_MOVE;
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ entity e = world;
+ while ( ( e = findentity(e,owner,minigame) ) )
+ if ( e.classname == "minigame_board_piece" )
+ remove(e);
+
+ qto_setup_pieces(minigame);
+#ifdef SVQC
+ if(minigame.minigame_players)
+ {
+ minigame.minigame_players.qto_moves = 0;
+ minigame.minigame_players.SendFlags |= QTO_SF_PLAYERSCORE;
+ }
+#endif
+}
+
+#ifdef SVQC
+
+
+// required function, handle server side events
+int qto_server_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "start":
+ {
+ qto_setup_pieces(minigame);
+ minigame.minigame_flags = QTO_TURN_MOVE;
+ return true;
+ }
+ case "end":
+ {
+ entity e = world;
+ while( (e = findentity(e, owner, minigame)) )
+ if(e.classname == "minigame_board_piece")
+ {
+ if(e.netname) { strunzone(e.netname); }
+ remove(e);
+ }
+ return false;
+ }
+ case "join":
+ {
+ int pl_num = minigame_count_players(minigame);
+
+ // Don't allow more than 1 player
+ if(pl_num >= 1) { return false; }
+
+ // Team 1 by default
+ return 1;
+ }
+ case "cmd":
+ {
+ switch(argv(0))
+ {
+ case "move":
+ qto_move(minigame, ...(0,entity), ...(1,int) == 2 ? argv(1) : string_null );
+ return true;
+ case "restart":
+ qto_restart_match(minigame,...(0,entity));
+ return true;
+ }
+
+ return false;
+ }
+ case "network_send":
+ {
+ entity sent = ...(0,entity);
+ int sf = ...(1,int);
+ if ( sent.classname == "minigame_board_piece" && (sf & MINIG_SF_UPDATE) )
+ {
+ WriteByte(MSG_ENTITY,sent.cnt);
+ }
+ else if ( sent.classname == "minigame_player" && (sf & QTO_SF_PLAYERSCORE ) )
+ {
+ WriteLong(MSG_ENTITY,sent.qto_moves);
+ }
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+#elif defined(CSQC)
+
+string qto_curr_pos; // identifier of the tile under the mouse
+vector qto_boardpos; // HUD board position
+vector qto_boardsize;// HUD board size
+
+// Required function, draw the game board
+void qto_hud_board(vector pos, vector mySize)
+{
+ minigame_hud_fitsqare(pos, mySize);
+ qto_boardpos = pos;
+ qto_boardsize = mySize;
+
+ minigame_hud_simpleboard(pos,mySize,minigame_texture("qto/board"));
+
+ vector tile_size = minigame_hud_denormalize_size('1 1 0' / QTO_TILE_SIZE,pos,mySize);
+ vector tile_pos;
+
+ bool valid = qto_valid_tile(qto_curr_pos);
+ int number = minigame_tile_number(qto_curr_pos);
+ int letter = minigame_tile_letter(qto_curr_pos);
+ string pos1 = minigame_tile_buildname(letter-1,number);
+ string pos2 = minigame_tile_buildname(letter+1,number);
+ string pos3 = minigame_tile_buildname(letter,number-1);
+ string pos4 = minigame_tile_buildname(letter,number+1);
+
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_board_piece" )
+ {
+ tile_pos = minigame_tile_pos(e.netname,QTO_NUM_CNT,QTO_LET_CNT);
+ tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+
+ vector tile_color = '0.4 0.4 0.4';
+
+ if(valid)
+ switch(e.netname)
+ {
+ case qto_curr_pos:
+ case pos1: case pos2: case pos3: case pos4:
+ tile_color = '0.8 0.8 0.8';
+ break;
+ }
+
+ minigame_drawpic_centered( tile_pos,
+ minigame_texture(strcat("qto/piece", ftos(e.cnt))),
+ tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+ }
+ }
+}
+
+
+// Required function, draw the game status panel
+void qto_hud_status(vector pos, vector mySize)
+{
+ HUD_Panel_DrawBg(1);
+ vector ts;
+ ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
+ hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
+
+ pos_y += ts_y;
+ mySize_y -= ts_y;
+
+ vector player_fontsize = hud_fontsize * 1.75;
+ ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
+ ts_x = mySize_x;
+ vector mypos;
+ vector tile_size = '48 48 0';
+
+ mypos = pos;
+ drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
+ mypos_y += player_fontsize_y;
+ drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
+
+ entity e;
+ FOREACH_MINIGAME_ENTITY(e)
+ {
+ if ( e.classname == "minigame_player" )
+ {
+ mypos = pos;
+ minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
+ GetPlayerName(e.minigame_playerslot-1),
+ player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ mypos_y += player_fontsize_y;
+ //drawpic( mypos,
+ // minigame_texture("qto/piece"),
+ // tile_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL );
+
+ //mypos_x += tile_size_x;
+
+ drawstring(mypos,sprintf(_("Moves: %s"), ftos(e.qto_moves)),'32 32 0',
+ '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ }
+}
+
+// Turn a set of flags into a help message
+string qto_turn_to_string(int turnflags)
+{
+ if ( turnflags & QTO_TURN_WIN )
+ return _("Well done, you win!");
+
+ if ( turnflags & QTO_TURN_MOVE )
+ return _("Turn all the angry faces into happy faces");
+
+ return "";
+}
+
+// Make the correct move
+void qto_make_move(entity minigame)
+{
+ if ( minigame.minigame_flags == QTO_TURN_MOVE )
+ {
+ minigame_cmd("move ",qto_curr_pos);
+ }
+}
+
+void qto_set_curr_pos(string s)
+{
+ if ( qto_curr_pos )
+ strunzone(qto_curr_pos);
+ if ( s )
+ s = strzone(s);
+ qto_curr_pos = s;
+}
+
+// Required function, handle client events
+int qto_client_event(entity minigame, string event, ...)
+{
+ switch(event)
+ {
+ case "activate":
+ {
+ qto_set_curr_pos("");
+ minigame.message = qto_turn_to_string(minigame.minigame_flags);
+ return false;
+ }
+ case "key_pressed":
+ {
+ //if((minigame.minigame_flags & QTO_TURN_TEAM) == minigame_self.team)
+ {
+ switch ( ...(0,int) )
+ {
+ case K_RIGHTARROW:
+ case K_KP_RIGHTARROW:
+ if ( ! qto_curr_pos )
+ qto_set_curr_pos("a3");
+ else
+ qto_set_curr_pos( minigame_relative_tile(qto_curr_pos,1,0,QTO_NUM_CNT,QTO_LET_CNT));
+ return true;
+ case K_LEFTARROW:
+ case K_KP_LEFTARROW:
+ if ( ! qto_curr_pos )
+ qto_set_curr_pos("c3");
+ else
+ qto_set_curr_pos(minigame_relative_tile(qto_curr_pos,-1,0,QTO_NUM_CNT,QTO_LET_CNT));
+ return true;
+ case K_UPARROW:
+ case K_KP_UPARROW:
+ if ( ! qto_curr_pos )
+ qto_set_curr_pos("a1");
+ else
+ qto_set_curr_pos(minigame_relative_tile(qto_curr_pos,0,1,QTO_NUM_CNT,QTO_LET_CNT));
+ return true;
+ case K_DOWNARROW:
+ case K_KP_DOWNARROW:
+ if ( ! qto_curr_pos )
+ qto_set_curr_pos("a3");
+ else
+ qto_set_curr_pos(minigame_relative_tile(qto_curr_pos,0,-1,QTO_NUM_CNT,QTO_LET_CNT));
+ return true;
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_SPACE:
+ qto_make_move(minigame);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ case "mouse_pressed":
+ {
+ if(...(0,int) == K_MOUSE1)
+ {
+ qto_make_move(minigame);
+ return true;
+ }
+
+ return false;
+ }
+ case "mouse_moved":
+ {
+ vector mouse_pos = minigame_hud_normalize(mousepos,qto_boardpos,qto_boardsize);
+ if ( minigame.minigame_flags == QTO_TURN_MOVE )
+ {
+ qto_set_curr_pos(minigame_tile_name(mouse_pos,QTO_NUM_CNT,QTO_LET_CNT));
+ }
+ if ( ! qto_valid_tile(qto_curr_pos) )
+ qto_set_curr_pos("");
+
+ return true;
+ }
+ case "network_receive":
+ {
+ entity sent = ...(0,entity);
+ int sf = ...(1,int);
+ if ( sent.classname == "minigame" )
+ {
+ if ( sf & MINIG_SF_UPDATE )
+ {
+ sent.message = qto_turn_to_string(sent.minigame_flags);
+ if ( sent.minigame_flags & minigame_self.team )
+ minigame_prompt();
+ }
+ }
+ else if(sent.classname == "minigame_board_piece")
+ {
+ if(sf & MINIG_SF_UPDATE)
+ {
+ sent.cnt = ReadByte();
+ }
+ }
+ else if ( sent.classname == "minigame_player" && (sf & QTO_SF_PLAYERSCORE ) )
+ {
+ sent.qto_moves = ReadLong();
+ }
+
+ return false;
+ }
+ case "menu_show":
+ {
+ HUD_MinigameMenu_CustomEntry(...(0,entity),_("Restart"),"restart");
+ return false;
+ }
+ case "menu_click":
+ {
+ if(...(0,string) == "restart")
+ minigame_cmd("restart");
+ return false;
+ }
+ }
+
+ return false;
+}
+
+#endif
\ No newline at end of file
return curr_team % n_teams + 1;
}
+// Get the previous team number
+int minigame_prev_team(int curr_team, int n_teams)
+{
+ return curr_team % n_teams - 1;
+}
+
// set send flags only when on server
// (for example in game logic which can be used both in client and server
void minigame_server_sendflags(entity ent, int mgflags)
#endif
pl_num++;
return pl_num;
-}
\ No newline at end of file
+}
// Get the next team number (note: team numbers are between 1 and n_teams, inclusive)
int minigame_next_team(int curr_team, int n_teams);
+// Get the previous team number
+int minigame_prev_team(int curr_team, int n_teams);
+
// set send flags only when on server
// (for example in game logic which can be used both in client and server
void minigame_server_sendflags(entity ent, int mgflags);