2 REGISTER_MINIGAME(ps, _("Peg Solitaire"));
4 const float PS_TURN_MOVE = 0x0100; // player has to click on a piece on the board
5 const float PS_TURN_WIN = 0x0200; // player has won
6 const float PS_TURN_DRAW = 0x0400; // player can make no more moves
7 const float PS_TURN_TYPE = 0x0f00; // turn type mask
9 const int PS_LET_CNT = 7;
10 const int PS_NUM_CNT = 7;
12 const int PS_TILE_SIZE = 8;
14 // find same game piece given its tile name
15 entity ps_find_piece(entity minig, string tile)
18 while ( ( e = findentity(e,owner,minig) ) )
19 if ( e.classname == "minigame_board_piece" && e.netname == tile )
24 bool ps_draw(entity minigame)
28 while( ( e = findentity(e,owner,minigame) ) )
29 if( e.classname == "minigame_board_piece" )
34 return ((valid > 0) ? true : false);
37 bool ps_tile_blacklisted(string tile)
39 int number = minigame_tile_number(tile);
40 int letter = minigame_tile_letter(tile);
45 else if(number > PS_NUM_CNT - 3)
48 if(letter > PS_LET_CNT - 3)
52 else if(number > PS_NUM_CNT - 3)
59 // check if the tile name is valid (5x5 grid)
60 bool ps_valid_tile(string tile)
64 if(ps_tile_blacklisted(tile))
66 float number = minigame_tile_number(tile);
67 float letter = minigame_tile_letter(tile);
68 return 0 <= number && number < PS_NUM_CNT && 0 <= letter && letter < PS_LET_CNT;
71 // Checks if the given piece completes a row
72 bool ps_winning_piece(entity minigame)
74 //int number = minigame_tile_number(piece.netname);
75 //int letter = minigame_tile_letter(piece.netname);
78 while ( ( e = findentity(e,owner,minigame) ) )
79 if ( e.classname == "minigame_board_piece" )
81 int number = minigame_tile_number(e.netname);
82 int letter = minigame_tile_letter(e.netname);
83 string try = minigame_tile_buildname(letter - 1, number);
84 if(ps_find_piece(minigame,try))
86 try = minigame_tile_buildname(letter - 2, number);
87 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
88 return false; // a move is valid, abort!
90 try = minigame_tile_buildname(letter + 1, number);
91 if(ps_find_piece(minigame,try))
93 try = minigame_tile_buildname(letter + 2, number);
94 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
95 return false; // a move is valid, abort!
97 try = minigame_tile_buildname(letter, number - 1);
98 if(ps_find_piece(minigame,try))
100 try = minigame_tile_buildname(letter, number - 2);
101 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
102 return false; // a move is valid, abort!
104 try = minigame_tile_buildname(letter, number + 1);
105 if(ps_find_piece(minigame,try))
107 try = minigame_tile_buildname(letter, number + 2);
108 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
109 return false; // a move is valid, abort!
116 void ps_setup_pieces(entity minigame)
119 for(i = 0; i < PS_NUM_CNT; ++i)
120 for(t = 0; t < PS_LET_CNT; ++t)
122 string try = minigame_tile_buildname(i,t);
123 if(!ps_valid_tile(try))
125 if(i == floor(PS_NUM_CNT * 0.5) && t == floor(PS_LET_CNT * 0.5))
126 continue; // middle piece is empty
127 entity piece = msle_spawn(minigame,new(minigame_board_piece));
128 piece.team = 1; // init default team?
129 piece.netname = strzone(minigame_tile_buildname(t,i));
130 minigame_server_sendflags(piece,MINIG_SF_ALL);
133 minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
136 bool ps_move_piece(entity minigame, entity piece, string pos, int leti, int numb)
140 if(ps_find_piece(minigame, pos))
142 entity middle = ps_find_piece(minigame, minigame_tile_buildname(leti,numb));
146 strfree(middle.netname);
149 strcpy(piece.netname, pos);
151 minigame_server_sendflags(piece,MINIG_SF_ALL);
157 void ps_move(entity minigame, entity player, string thepiece, string pos )
159 if ( minigame.minigame_flags & PS_TURN_MOVE )
162 if ( ps_valid_tile(pos) )
163 if ( !ps_find_piece(minigame, pos) && ps_find_piece(minigame, thepiece) )
165 entity piece = ps_find_piece(minigame, thepiece);
166 int number = minigame_tile_number(thepiece);
167 int letter = minigame_tile_letter(thepiece);
171 try = minigame_tile_buildname(letter-1,number);
172 if(ps_find_piece(minigame,try))
174 try = minigame_tile_buildname(letter-2,number);
175 if(ps_valid_tile(try) && try == pos)
176 done = ps_move_piece(minigame, piece, pos, letter - 1, number);
178 try = minigame_tile_buildname(letter+1,number);
179 if(!done && ps_find_piece(minigame,try))
181 try = minigame_tile_buildname(letter+2,number);
182 if(ps_valid_tile(try) && try == pos)
183 done = ps_move_piece(minigame, piece, pos, letter + 1, number);
185 try = minigame_tile_buildname(letter,number-1);
186 if(!done && ps_find_piece(minigame,try))
188 try = minigame_tile_buildname(letter,number-2);
189 if(ps_valid_tile(try) && try == pos)
190 done = ps_move_piece(minigame, piece, pos, letter, number - 1);
192 try = minigame_tile_buildname(letter,number+1);
193 if(!done && ps_find_piece(minigame,try))
195 try = minigame_tile_buildname(letter,number+2);
196 if(ps_valid_tile(try) && try == pos)
197 done = ps_move_piece(minigame, piece, pos, letter, number + 1);
201 return; // didn't make a move
203 minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
205 if ( ps_winning_piece(minigame) )
207 if(ps_draw(minigame))
208 minigame.minigame_flags = PS_TURN_DRAW;
210 minigame.minigame_flags = PS_TURN_WIN;
213 minigame.minigame_flags = PS_TURN_MOVE;
221 // required function, handle server side events
222 int ps_server_event(entity minigame, string event, ...)
228 ps_setup_pieces(minigame);
229 minigame.minigame_flags = PS_TURN_MOVE;
235 while( (e = findentity(e, owner, minigame)) )
236 if(e.classname == "minigame_board_piece")
245 int pl_num = minigame_count_players(minigame);
247 // Don't allow more than 1 player
248 if(pl_num >= 1) { return false; }
259 ps_move(minigame, ...(0,entity), (...(1,int) == 3 ? argv(1) : string_null), (...(1,int) == 3 ? argv(2) : string_null));
273 entity ps_curr_piece; // identifier for the currently selected piece
274 string ps_curr_pos; // identifier of the tile under the mouse
275 vector ps_boardpos; // HUD board position
276 vector ps_boardsize;// HUD board size
278 // Required function, draw the game board
279 void ps_hud_board(vector pos, vector mySize)
281 minigame_hud_fitsqare(pos, mySize);
283 ps_boardsize = mySize;
285 minigame_hud_simpleboard(pos,mySize,minigame_texture("ps/board"));
287 vector tile_size = minigame_hud_denormalize_size('1 1 0' / PS_TILE_SIZE,pos,mySize);
290 bool valid = ps_valid_tile(ps_curr_pos);
291 bool highlight = false;
295 int number = minigame_tile_number(ps_curr_pos);
296 int letter = minigame_tile_letter(ps_curr_pos);
297 try = minigame_tile_buildname(letter-1,number);
298 if(ps_find_piece(active_minigame,try))
300 try = minigame_tile_buildname(letter-2,number);
301 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
304 try = minigame_tile_buildname(letter+1,number);
305 if(ps_find_piece(active_minigame,try))
307 try = minigame_tile_buildname(letter+2,number);
308 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
311 try = minigame_tile_buildname(letter,number-1);
312 if(ps_find_piece(active_minigame,try))
314 try = minigame_tile_buildname(letter,number-2);
315 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
318 try = minigame_tile_buildname(letter,number+1);
319 if(ps_find_piece(active_minigame,try))
321 try = minigame_tile_buildname(letter,number+2);
322 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
326 bool draw_pos = false;
327 if(ps_curr_piece && valid && !ps_find_piece(active_minigame, ps_curr_pos))
330 int numb = minigame_tile_number(ps_curr_piece.netname);
331 int leti = minigame_tile_letter(ps_curr_piece.netname);
333 try = minigame_tile_buildname(leti-1,numb);
334 if(ps_find_piece(active_minigame,try))
336 try = minigame_tile_buildname(leti-2,numb);
337 if(try == ps_curr_pos)
340 try = minigame_tile_buildname(leti+1,numb);
341 if(ps_find_piece(active_minigame,try))
343 try = minigame_tile_buildname(leti+2,numb);
344 if(try == ps_curr_pos)
347 try = minigame_tile_buildname(leti,numb-1);
348 if(ps_find_piece(active_minigame,try))
350 try = minigame_tile_buildname(leti,numb-2);
351 if(try == ps_curr_pos)
354 try = minigame_tile_buildname(leti,numb+1);
355 if(ps_find_piece(active_minigame,try))
357 try = minigame_tile_buildname(leti,numb+2);
358 if(try == ps_curr_pos)
364 FOREACH_MINIGAME_ENTITY(e)
366 if ( e.classname == "minigame_board_piece" )
368 tile_pos = minigame_tile_pos(e.netname,PS_NUM_CNT,PS_LET_CNT);
369 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
371 vector tile_color = '1 1 1';
374 if(e.netname == ps_curr_pos)
375 if(ps_curr_piece.netname != ps_curr_pos)
377 minigame_drawpic_centered( tile_pos,
378 minigame_texture("ps/tile_available"),
379 tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
381 if(e == ps_curr_piece)
383 minigame_drawpic_centered( tile_pos,
384 minigame_texture("ps/tile_selected"),
385 tile_size, tile_color, panel_fg_alpha, DRAWFLAG_ADDITIVE );
388 minigame_drawpic_centered( tile_pos,
389 minigame_texture("ps/piece"),
390 tile_size * 0.8, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
396 tile_pos = minigame_tile_pos(ps_curr_pos,PS_NUM_CNT,PS_LET_CNT);
397 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
399 minigame_drawpic_centered(tile_pos,
400 minigame_texture("ps/piece"),
401 tile_size * 0.8, '0.5 0.5 0.5', panel_fg_alpha, DRAWFLAG_NORMAL);
404 if ( ( active_minigame.minigame_flags & PS_TURN_WIN ) || ( active_minigame.minigame_flags & PS_TURN_DRAW ) )
407 FOREACH_MINIGAME_ENTITY(e)
408 if(e.classname == "minigame_board_piece")
411 vector winfs = hud_fontsize*2;
412 string remaining_text;
413 if(active_minigame.minigame_flags & PS_TURN_WIN)
414 remaining_text = _("All pieces cleared!");
416 remaining_text = strcat(_("Remaining pieces:"), " ", ftos(remaining));
418 vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
420 win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
421 strcat(_("Game over!"), " ", remaining_text),
422 winfs, 0, DRAWFLAG_NORMAL, 0.5);
424 drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
426 minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
427 strcat(_("Game over!"), " ", remaining_text),
428 winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
433 // Required function, draw the game status panel
434 void ps_hud_status(vector pos, vector mySize)
438 ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
439 hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
444 vector player_fontsize = hud_fontsize * 1.75;
445 ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
448 vector tile_size = '48 48 0';
451 drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
452 mypos_y += player_fontsize_y;
453 drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
457 FOREACH_MINIGAME_ENTITY(e)
459 if(e.classname == "minigame_board_piece")
465 FOREACH_MINIGAME_ENTITY(e)
467 if ( e.classname == "minigame_player" )
470 minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
471 entcs_GetName(e.minigame_playerslot-1),
472 player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
474 mypos_y += player_fontsize_y;
476 // minigame_texture("ps/piece"),
477 // tile_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL );
479 //mypos_x += tile_size_x;
481 drawstring(mypos,sprintf(_("Pieces left: %s"), ftos(remaining)),'28 28 0',
482 '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
487 // Turn a set of flags into a help message
488 string ps_turn_to_string(int turnflags)
490 if (turnflags & PS_TURN_DRAW )
491 return _("No more valid moves");
493 if ( turnflags & PS_TURN_WIN )
494 return _("Well done, you win!");
496 if ( turnflags & PS_TURN_MOVE )
497 return _("Jump a piece over another to capture it");
502 // Make the correct move
503 void ps_make_move(entity minigame)
505 if ( minigame.minigame_flags == PS_TURN_MOVE )
507 entity piece = ps_find_piece(minigame,ps_curr_pos);
508 if(!ps_curr_piece || piece)
509 ps_curr_piece = ps_find_piece(minigame,ps_curr_pos);
512 minigame_cmd("move ", ps_curr_piece.netname, " ", ps_curr_pos);
513 ps_curr_piece = NULL;
518 void ps_set_curr_pos(string s)
520 strfree(ps_curr_pos);
526 // Required function, handle client events
527 int ps_client_event(entity minigame, string event, ...)
534 ps_curr_piece = NULL;
535 strcpy(minigame.message, ps_turn_to_string(minigame.minigame_flags));
540 strfree(minigame.message);
545 //if((minigame.minigame_flags & PS_TURN_TEAM) == minigame_self.team)
547 switch ( ...(0,int) )
550 case K_KP_RIGHTARROW:
552 ps_set_curr_pos("a3");
554 ps_set_curr_pos( minigame_relative_tile(ps_curr_pos,1,0,PS_NUM_CNT,PS_LET_CNT));
559 ps_set_curr_pos("c3");
561 ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,-1,0,PS_NUM_CNT,PS_LET_CNT));
566 ps_set_curr_pos("a1");
568 ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,0,1,PS_NUM_CNT,PS_LET_CNT));
573 ps_set_curr_pos("a3");
575 ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,0,-1,PS_NUM_CNT,PS_LET_CNT));
580 ps_make_move(minigame);
587 case "mouse_pressed":
589 if(...(0,int) == K_MOUSE1)
591 ps_make_move(minigame);
599 vector mouse_pos = minigame_hud_normalize(mousepos,ps_boardpos,ps_boardsize);
600 if ( minigame.minigame_flags == PS_TURN_MOVE )
602 ps_set_curr_pos(minigame_tile_name(mouse_pos,PS_NUM_CNT,PS_LET_CNT));
604 if ( ! ps_valid_tile(ps_curr_pos) )
609 case "network_receive":
611 entity sent = ...(0,entity);
613 if ( sent.classname == "minigame" )
615 if ( sf & MINIG_SF_UPDATE )
617 strcpy(sent.message, ps_turn_to_string(sent.minigame_flags));
618 //if ( sent.minigame_flags & minigame_self.team )