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);
44 else if(number > PS_NUM_CNT - 3)
46 if(letter > PS_LET_CNT - 3)
49 else if(number > PS_NUM_CNT - 3)
55 // check if the tile name is valid (5x5 grid)
56 bool ps_valid_tile(string tile)
60 if(ps_tile_blacklisted(tile))
62 float number = minigame_tile_number(tile);
63 float letter = minigame_tile_letter(tile);
64 return 0 <= number && number < PS_NUM_CNT && 0 <= letter && letter < PS_LET_CNT;
67 // Checks if the given piece completes a row
68 bool ps_winning_piece(entity minigame)
70 //int number = minigame_tile_number(piece.netname);
71 //int letter = minigame_tile_letter(piece.netname);
74 while ( ( e = findentity(e,owner,minigame) ) )
75 if ( e.classname == "minigame_board_piece" )
77 int number = minigame_tile_number(e.netname);
78 int letter = minigame_tile_letter(e.netname);
79 string try = minigame_tile_buildname(letter - 1, number);
80 if(ps_find_piece(minigame,try))
82 try = minigame_tile_buildname(letter - 2, number);
83 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
84 return false; // a move is valid, abort!
86 try = minigame_tile_buildname(letter + 1, number);
87 if(ps_find_piece(minigame,try))
89 try = minigame_tile_buildname(letter + 2, number);
90 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
91 return false; // a move is valid, abort!
93 try = minigame_tile_buildname(letter, number - 1);
94 if(ps_find_piece(minigame,try))
96 try = minigame_tile_buildname(letter, number - 2);
97 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
98 return false; // a move is valid, abort!
100 try = minigame_tile_buildname(letter, number + 1);
101 if(ps_find_piece(minigame,try))
103 try = minigame_tile_buildname(letter, number + 2);
104 if(ps_valid_tile(try) && !ps_find_piece(minigame,try))
105 return false; // a move is valid, abort!
112 void ps_setup_pieces(entity minigame)
115 for(i = 0; i < PS_NUM_CNT; ++i)
116 for(t = 0; t < PS_LET_CNT; ++t)
118 string try = minigame_tile_buildname(i,t);
119 if(!ps_valid_tile(try))
121 if(i == floor(PS_NUM_CNT * 0.5) && t == floor(PS_LET_CNT * 0.5))
122 continue; // middle piece is empty
123 entity piece = msle_spawn(minigame,"minigame_board_piece");
124 piece.team = 1; // init default team?
125 piece.netname = strzone(minigame_tile_buildname(t,i));
126 minigame_server_sendflags(piece,MINIG_SF_ALL);
129 minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
132 bool ps_move_piece(entity minigame, entity piece, string pos, int leti, int numb)
136 if(ps_find_piece(minigame, pos))
138 entity middle = ps_find_piece(minigame, minigame_tile_buildname(leti,numb));
142 if(middle.netname) { strunzone(middle.netname); }
145 if(piece.netname) { strunzone(piece.netname); }
146 piece.netname = strzone(pos);
148 minigame_server_sendflags(piece,MINIG_SF_ALL);
154 void ps_move(entity minigame, entity player, string thepiece, string pos )
156 if ( minigame.minigame_flags & PS_TURN_MOVE )
159 if ( ps_valid_tile(pos) )
160 if ( !ps_find_piece(minigame, pos) && ps_find_piece(minigame, thepiece) )
162 entity piece = ps_find_piece(minigame, thepiece);
163 int number = minigame_tile_number(thepiece);
164 int letter = minigame_tile_letter(thepiece);
168 try = minigame_tile_buildname(letter-1,number);
169 if(ps_find_piece(minigame,try))
171 try = minigame_tile_buildname(letter-2,number);
172 if(ps_valid_tile(try) && try == pos)
173 done = ps_move_piece(minigame, piece, pos, letter - 1, number);
175 try = minigame_tile_buildname(letter+1,number);
176 if(!done && ps_find_piece(minigame,try))
178 try = minigame_tile_buildname(letter+2,number);
179 if(ps_valid_tile(try) && try == pos)
180 done = ps_move_piece(minigame, piece, pos, letter + 1, number);
182 try = minigame_tile_buildname(letter,number-1);
183 if(!done && ps_find_piece(minigame,try))
185 try = minigame_tile_buildname(letter,number-2);
186 if(ps_valid_tile(try) && try == pos)
187 done = ps_move_piece(minigame, piece, pos, letter, number - 1);
189 try = minigame_tile_buildname(letter,number+1);
190 if(!done && ps_find_piece(minigame,try))
192 try = minigame_tile_buildname(letter,number+2);
193 if(ps_valid_tile(try) && try == pos)
194 done = ps_move_piece(minigame, piece, pos, letter, number + 1);
198 return; // didn't make a move
200 minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
202 if ( ps_winning_piece(minigame) )
204 if(ps_draw(minigame))
205 minigame.minigame_flags = PS_TURN_DRAW;
207 minigame.minigame_flags = PS_TURN_WIN;
210 minigame.minigame_flags = PS_TURN_MOVE;
218 // required function, handle server side events
219 int ps_server_event(entity minigame, string event, ...)
225 ps_setup_pieces(minigame);
226 minigame.minigame_flags = PS_TURN_MOVE;
232 while( (e = findentity(e, owner, minigame)) )
233 if(e.classname == "minigame_board_piece")
235 if(e.netname) { strunzone(e.netname); }
242 int pl_num = minigame_count_players(minigame);
244 // Don't allow more than 1 player
245 if(pl_num >= 1) { return false; }
256 ps_move(minigame, ...(0,entity), (...(1,int) == 3 ? argv(1) : string_null), (...(1,int) == 3 ? argv(2) : string_null));
270 entity ps_curr_piece; // identifier for the currently selected piece
271 string ps_curr_pos; // identifier of the tile under the mouse
272 vector ps_boardpos; // HUD board position
273 vector ps_boardsize;// HUD board size
275 // Required function, draw the game board
276 void ps_hud_board(vector pos, vector mySize)
278 minigame_hud_fitsqare(pos, mySize);
280 ps_boardsize = mySize;
282 minigame_hud_simpleboard(pos,mySize,minigame_texture("ps/board"));
284 vector tile_size = minigame_hud_denormalize_size('1 1 0' / PS_TILE_SIZE,pos,mySize);
287 bool valid = ps_valid_tile(ps_curr_pos);
288 bool highlight = false;
292 int number = minigame_tile_number(ps_curr_pos);
293 int letter = minigame_tile_letter(ps_curr_pos);
294 try = minigame_tile_buildname(letter-1,number);
295 if(ps_find_piece(active_minigame,try))
297 try = minigame_tile_buildname(letter-2,number);
298 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
301 try = minigame_tile_buildname(letter+1,number);
302 if(ps_find_piece(active_minigame,try))
304 try = minigame_tile_buildname(letter+2,number);
305 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
308 try = minigame_tile_buildname(letter,number-1);
309 if(ps_find_piece(active_minigame,try))
311 try = minigame_tile_buildname(letter,number-2);
312 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
315 try = minigame_tile_buildname(letter,number+1);
316 if(ps_find_piece(active_minigame,try))
318 try = minigame_tile_buildname(letter,number+2);
319 if(ps_valid_tile(try) && !ps_find_piece(active_minigame,try))
323 bool draw_pos = false;
324 if(ps_curr_piece && valid && !ps_find_piece(active_minigame, ps_curr_pos))
327 int numb = minigame_tile_number(ps_curr_piece.netname);
328 int leti = minigame_tile_letter(ps_curr_piece.netname);
330 try = minigame_tile_buildname(leti-1,numb);
331 if(ps_find_piece(active_minigame,try))
333 try = minigame_tile_buildname(leti-2,numb);
334 if(try == ps_curr_pos)
337 try = minigame_tile_buildname(leti+1,numb);
338 if(ps_find_piece(active_minigame,try))
340 try = minigame_tile_buildname(leti+2,numb);
341 if(try == ps_curr_pos)
344 try = minigame_tile_buildname(leti,numb-1);
345 if(ps_find_piece(active_minigame,try))
347 try = minigame_tile_buildname(leti,numb-2);
348 if(try == ps_curr_pos)
351 try = minigame_tile_buildname(leti,numb+1);
352 if(ps_find_piece(active_minigame,try))
354 try = minigame_tile_buildname(leti,numb+2);
355 if(try == ps_curr_pos)
361 FOREACH_MINIGAME_ENTITY(e)
363 if ( e.classname == "minigame_board_piece" )
365 tile_pos = minigame_tile_pos(e.netname,PS_NUM_CNT,PS_LET_CNT);
366 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
368 vector tile_color = '1 1 1';
371 if(e.netname == ps_curr_pos)
372 if(ps_curr_piece.netname != ps_curr_pos)
374 minigame_drawpic_centered( tile_pos,
375 minigame_texture("ps/tile_available"),
376 tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
378 if(e == ps_curr_piece)
380 minigame_drawpic_centered( tile_pos,
381 minigame_texture("ps/tile_selected"),
382 tile_size, tile_color, panel_fg_alpha, DRAWFLAG_ADDITIVE );
385 minigame_drawpic_centered( tile_pos,
386 minigame_texture("ps/piece"),
387 tile_size * 0.8, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
393 tile_pos = minigame_tile_pos(ps_curr_pos,PS_NUM_CNT,PS_LET_CNT);
394 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
396 minigame_drawpic_centered(tile_pos,
397 minigame_texture("ps/piece"),
398 tile_size * 0.8, '0.5 0.5 0.5', panel_fg_alpha, DRAWFLAG_NORMAL);
401 if ( ( active_minigame.minigame_flags & PS_TURN_WIN ) || ( active_minigame.minigame_flags & PS_TURN_DRAW ) )
404 FOREACH_MINIGAME_ENTITY(e)
405 if(e.classname == "minigame_board_piece")
408 vector winfs = hud_fontsize*2;
409 string remaining_text;
410 if(active_minigame.minigame_flags & PS_TURN_WIN)
411 remaining_text = "All pieces cleared!";
413 remaining_text = strcat("Remaining pieces: ", ftos(remaining));
415 vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
417 win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
418 sprintf("Game over! %s", remaining_text),
419 winfs, 0, DRAWFLAG_NORMAL, 0.5);
421 drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
423 minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
424 sprintf("Game over! %s", remaining_text),
425 winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
430 // Required function, draw the game status panel
431 void ps_hud_status(vector pos, vector mySize)
435 ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
436 hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
441 vector player_fontsize = hud_fontsize * 1.75;
442 ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
445 vector tile_size = '48 48 0';
448 drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
449 mypos_y += player_fontsize_y;
450 drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
454 FOREACH_MINIGAME_ENTITY(e)
456 if(e.classname == "minigame_board_piece")
462 FOREACH_MINIGAME_ENTITY(e)
464 if ( e.classname == "minigame_player" )
467 minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
468 entcs_GetName(e.minigame_playerslot-1),
469 player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
471 mypos_y += player_fontsize_y;
473 // minigame_texture("ps/piece"),
474 // tile_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL );
476 //mypos_x += tile_size_x;
478 drawstring(mypos,sprintf(_("Pieces left: %s"), ftos(remaining)),'28 28 0',
479 '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
484 // Turn a set of flags into a help message
485 string ps_turn_to_string(int turnflags)
487 if (turnflags & PS_TURN_DRAW )
488 return _("No more valid moves");
490 if ( turnflags & PS_TURN_WIN )
491 return _("Well done, you win!");
493 if ( turnflags & PS_TURN_MOVE )
494 return _("Jump a piece over another to capture it");
499 // Make the correct move
500 void ps_make_move(entity minigame)
502 if ( minigame.minigame_flags == PS_TURN_MOVE )
504 entity piece = ps_find_piece(minigame,ps_curr_pos);
505 if(!ps_curr_piece || piece)
506 ps_curr_piece = ps_find_piece(minigame,ps_curr_pos);
509 minigame_cmd("move ", ps_curr_piece.netname, " ", ps_curr_pos);
510 ps_curr_piece = NULL;
515 void ps_set_curr_pos(string s)
518 strunzone(ps_curr_pos);
524 // Required function, handle client events
525 int ps_client_event(entity minigame, string event, ...)
532 ps_curr_piece = NULL;
533 minigame.message = ps_turn_to_string(minigame.minigame_flags);
538 //if((minigame.minigame_flags & PS_TURN_TEAM) == minigame_self.team)
540 switch ( ...(0,int) )
543 case K_KP_RIGHTARROW:
545 ps_set_curr_pos("a3");
547 ps_set_curr_pos( minigame_relative_tile(ps_curr_pos,1,0,PS_NUM_CNT,PS_LET_CNT));
552 ps_set_curr_pos("c3");
554 ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,-1,0,PS_NUM_CNT,PS_LET_CNT));
559 ps_set_curr_pos("a1");
561 ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,0,1,PS_NUM_CNT,PS_LET_CNT));
566 ps_set_curr_pos("a3");
568 ps_set_curr_pos(minigame_relative_tile(ps_curr_pos,0,-1,PS_NUM_CNT,PS_LET_CNT));
573 ps_make_move(minigame);
580 case "mouse_pressed":
582 if(...(0,int) == K_MOUSE1)
584 ps_make_move(minigame);
592 vector mouse_pos = minigame_hud_normalize(mousepos,ps_boardpos,ps_boardsize);
593 if ( minigame.minigame_flags == PS_TURN_MOVE )
595 ps_set_curr_pos(minigame_tile_name(mouse_pos,PS_NUM_CNT,PS_LET_CNT));
597 if ( ! ps_valid_tile(ps_curr_pos) )
602 case "network_receive":
604 entity sent = ...(0,entity);
606 if ( sent.classname == "minigame" )
608 if ( sf & MINIG_SF_UPDATE )
610 sent.message = ps_turn_to_string(sent.minigame_flags);
611 if ( sent.minigame_flags & minigame_self.team )