]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/minigames/minigame/nmm.qc
Minigame code and cfg
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / minigames / minigame / nmm.qc
1 const float NMM_TURN_PLACE = 0x0100; // player has to place a piece on the board
2 const float NMM_TURN_MOVE  = 0x0200; // player has to move a piece by one tile
3 const float NMM_TURN_FLY   = 0x0400; // player has to move a piece anywhere
4 const float NMM_TURN_TAKE  = 0x0800; // player has to take a non-mill piece
5 const float NMM_TURN_TAKEANY=0x1000; // combine with NMM_TURN_TAKE, can take mill pieces
6 const float NMM_TURN_WIN   = 0x2000; // player has won
7 const float NMM_TURN_TYPE  = 0xff00;
8 const float NMM_TURN_TEAM1 = 0x0001;
9 const float NMM_TURN_TEAM2 = 0x0002;
10 const float NMM_TURN_TEAM  = 0x00ff;
11
12 const float NMM_PIECE_DEAD  = 0x0; // captured by the enemy
13 const float NMM_PIECE_HOME  = 0x1; // not yet placed
14 const float NMM_PIECE_BOARD = 0x2; // placed on the board
15
16 .float  nmm_tile_distance;
17 .entity nmm_tile_piece;
18 .string nmm_tile_hmill;
19 .string nmm_tile_vmill;
20
21 // build a string containing the indices of the tile to check for a horizontal mill
22 string nmm_tile_build_hmill(entity tile)
23 {
24         float number = minigame_tile_number(tile.netname);
25         float letter = minigame_tile_letter(tile.netname);
26         if ( number == letter || number+letter == 6 )
27         {
28                 float add = letter < 3 ? 1 : -1;
29                 return strcat(tile.netname," ",
30                         minigame_tile_buildname(letter+add*tile.nmm_tile_distance,number)," ",
31                         minigame_tile_buildname(letter+add*2*tile.nmm_tile_distance,number) );
32         }
33         else if ( letter == 3 )
34                 return strcat(minigame_tile_buildname(letter-tile.nmm_tile_distance,number)," ",
35                         tile.netname," ",
36                         minigame_tile_buildname(letter+tile.nmm_tile_distance,number) );
37         else if ( letter < 3 )
38                 return strcat(minigame_tile_buildname(0,number)," ",
39                         minigame_tile_buildname(1,number)," ",
40                         minigame_tile_buildname(2,number) );
41         else
42                 return strcat(minigame_tile_buildname(4,number)," ",
43                         minigame_tile_buildname(5,number)," ",
44                         minigame_tile_buildname(6,number) );
45 }
46
47 // build a string containing the indices of the tile to check for a vertical mill
48 string nmm_tile_build_vmill(entity tile)
49 {
50         float letter = minigame_tile_letter(tile.netname);
51         float number = minigame_tile_number(tile.netname);
52         if ( letter == number || letter+number == 6 )
53         {
54                 float add = number < 3 ? 1 : -1;
55                 return strcat(tile.netname," ",
56                         minigame_tile_buildname(letter,number+add*tile.nmm_tile_distance)," ",
57                         minigame_tile_buildname(letter,number+add*2*tile.nmm_tile_distance) );
58         }
59         else if ( number == 3 )
60                 return strcat(minigame_tile_buildname(letter,number-tile.nmm_tile_distance)," ",
61                         tile.netname," ",
62                         minigame_tile_buildname(letter,number+tile.nmm_tile_distance) );
63         else if ( number < 3 )
64                 return strcat(minigame_tile_buildname(letter,0)," ",
65                         minigame_tile_buildname(letter,1)," ",
66                         minigame_tile_buildname(letter,2) );
67         else
68                 return strcat(minigame_tile_buildname(letter,4)," ",
69                         minigame_tile_buildname(letter,5)," ",
70                         minigame_tile_buildname(letter,6) );
71 }
72
73 // Create an new tile
74 // \param id       Tile index (eg: a1)
75 // \param minig    Owner minigame instance 
76 // \param distance Distance from adjacent tiles
77 void nmm_spawn_tile(string id, entity minig, float distance)
78 {
79         // TODO global variable + list_next for simpler tile loops
80         entity e = spawn();
81         e.origin = minigame_tile_pos(id,7,7);
82         e.classname = "minigame_nmm_tile";
83         e.netname = id;
84         e.owner = minig;
85         e.team = 0;
86         e.nmm_tile_distance = distance;
87         e.nmm_tile_hmill = strzone(nmm_tile_build_hmill(e));
88         e.nmm_tile_vmill = strzone(nmm_tile_build_vmill(e));
89 }
90
91 // Create a tile square and recursively create inner squares
92 // \param minig    Owner minigame instance 
93 // \param offset   Index offset (eg: 1 to start the square at b2, 0 at a1 etc.)
94 // \param skip     Number of indices to skip between tiles (eg 1: a1, a3)
95 void nmm_spawn_tile_square( entity minig, float offset, float skip )
96 {
97         float letter = offset;
98         float number = offset;
99         float i, j;
100         for ( i = 0; i < 3; i++ )
101         {
102                 number = offset;
103                 for ( j = 0; j < 3; j++ )
104                 {
105                         if ( i != 1 || j != 1 )
106                                 nmm_spawn_tile(strzone(minigame_tile_buildname(letter,number)),minig, skip+1);
107                         number += skip+1;
108                 }
109                 letter += skip+1;
110         }
111         
112         if ( skip > 0 )
113                 nmm_spawn_tile_square(minig,offset+1,skip-1);
114 }
115
116 // Remove tiles of a NMM minigame
117 void nmm_kill_tiles(entity minig)
118 {
119         entity e = world;
120         while ( ( e = findentity(e,owner,minig) ) )
121                 if ( e.classname == "minigame_nmm_tile" )
122                 {
123                         strunzone(e.netname);
124                         strunzone(e.nmm_tile_hmill);
125                         strunzone(e.nmm_tile_vmill);
126                         remove(e);
127                 }
128 }
129
130 // Create the tiles of a NMM minigame
131 void nmm_init_tiles(entity minig)
132 {
133         nmm_spawn_tile_square(minig,0,2);
134 }
135
136 // Find a tile by its id
137 entity nmm_find_tile(entity minig, string id)
138 {
139         entity e = world;
140         while ( ( e = findentity(e,owner,minig) ) )
141                 if ( e.classname == "minigame_nmm_tile" && e.netname == id )
142                         return e;
143         return world;
144 }
145
146 // Check whether two tiles are adjacent
147 float nmm_tile_adjacent(entity tile1, entity tile2)
148 {
149                 
150         float dnumber = fabs ( minigame_tile_number(tile1.netname) - minigame_tile_number(tile2.netname) );
151         float dletter = fabs ( minigame_tile_letter(tile1.netname) - minigame_tile_letter(tile2.netname) );
152         
153         return ( dnumber == 0 && ( dletter == 1 || dletter == tile1.nmm_tile_distance ) ) ||
154                 ( dletter == 0 && ( dnumber == 1 || dnumber == tile1.nmm_tile_distance ) );
155 }
156
157 // Returns 1 if there is at least 1 free adjacent tile
158 float nmm_tile_canmove(entity tile)
159 {
160         entity e = world;
161         while ( ( e = findentity(e,owner,tile.owner) ) )
162                 if ( e.classname == "minigame_nmm_tile" && !e.nmm_tile_piece 
163                                 && nmm_tile_adjacent(e,tile) )
164                 {
165                         return 1;
166                 }
167         return 0;
168 }
169
170 // Check if the given tile id appears in the string
171 float nmm_in_mill_string(entity tile, string s)
172 {
173         float argc = tokenize(s);
174         float i;
175         for ( i = 0; i < argc; i++ )
176         {
177                 entity e = nmm_find_tile(tile.owner,argv(i));
178                 if ( !e || !e.nmm_tile_piece || e.nmm_tile_piece.team != tile.nmm_tile_piece.team )
179                         return 0;
180         }
181         return 1;
182 }
183
184 // Check if a tile is in a mill
185 float nmm_in_mill(entity tile)
186 {
187         return tile.nmm_tile_piece &&  ( 
188                 nmm_in_mill_string(tile,tile.nmm_tile_hmill) ||
189                 nmm_in_mill_string(tile,tile.nmm_tile_vmill) );
190 }
191
192
193 #ifdef SVQC
194 // Find a NMM piece matching some of the given flags and team number
195 entity nmm_find_piece(entity start, entity minigame, float teamn, float pieceflags)
196 {
197         entity e = start;
198         while ( ( e = findentity(e,owner,minigame) ) )
199                 if ( e.classname == "minigame_board_piece" && 
200                                 (e.minigame_flags & pieceflags) && e.team == teamn )
201                         return e;
202         return world;
203 }
204
205 // Count NMM pieces matching flags and team number
206 float nmm_count_pieces(entity minigame, float teamn, float pieceflags)
207 {
208         float n = 0;
209         entity e = world;
210         while (( e = nmm_find_piece(e,minigame, teamn, pieceflags) ))
211                 n++;
212         return n;
213 }
214
215 // required function, handle server side events
216 float minigame_event_nmm(entity minigame, string event, ...)
217 {
218         if ( event == "start" )
219         {
220                 minigame.minigame_flags = NMM_TURN_PLACE|NMM_TURN_TEAM1;
221                 nmm_init_tiles(minigame);
222                 float i;
223                 entity e;
224                 for ( i = 0; i < 7; i++ )
225                 {
226                         e = msle_spawn(minigame,"minigame_board_piece");
227                         e.team = 1;
228                         e.minigame_flags = NMM_PIECE_HOME;
229                         e = msle_spawn(minigame,"minigame_board_piece");
230                         e.team = 2;
231                         e.minigame_flags = NMM_PIECE_HOME;
232                 }
233                         
234                 return 1;
235         }
236         else if ( event == "end" )
237         {
238                 nmm_kill_tiles(minigame);
239         }
240         else if ( event == "join" )
241         {
242                 float n = 0;
243                 entity e;
244                 for ( e = minigame.minigame_players; e; e = e.list_next )
245                         n++;
246                 if ( n >= 2 )
247                         return 0;
248                 if ( minigame.minigame_players && minigame.minigame_players.team == 1 )
249                         return 2;
250                 return 1;
251         }
252         else if ( event == "cmd" )
253         {
254                 entity e = ...(0,entity);
255                 float argc = ...(1,float);
256                 entity tile = world;
257                 entity piece = world;
258                 float move_ok = 0;
259                 
260                 if ( e && argc >= 2 && argv(0) == "move" && 
261                         ( minigame.minigame_flags & NMM_TURN_TEAM ) == e.team )
262                 {
263                         tile = nmm_find_tile(minigame,argv(1));
264                         if ( !tile )
265                         {
266                                 move_ok = 0;
267                         }
268                         else if ( minigame.minigame_flags & NMM_TURN_PLACE )
269                         {
270                                 piece = nmm_find_piece(world,minigame,e.team,NMM_PIECE_HOME);
271                                 if ( !tile.nmm_tile_piece && piece )
272                                 {
273                                         tile.nmm_tile_piece = piece;
274                                         piece.minigame_flags = NMM_PIECE_BOARD;
275                                         piece.origin = tile.origin;
276                                         piece.SendFlags |= MINIG_SF_UPDATE;
277                                         move_ok = 1;
278                                 }
279                         }
280                         else if ( minigame.minigame_flags & NMM_TURN_MOVE )
281                         {
282                                 if ( tile.nmm_tile_piece && tile.nmm_tile_piece.team == e.team )
283                                 {
284                                         piece = tile.nmm_tile_piece;
285                                         entity tile2 = nmm_find_tile(minigame,argv(2));
286                                         if ( tile2 && nmm_tile_adjacent(tile,tile2) && !tile2.nmm_tile_piece )
287                                         {
288                                                 tile.nmm_tile_piece = world;
289                                                 tile2.nmm_tile_piece = piece;
290                                                 piece.origin = tile2.origin;
291                                                 piece.SendFlags |= MINIG_SF_UPDATE;
292                                                 tile = tile2;
293                                                 move_ok = 1;
294                                         }
295                                 }
296                                 
297                         }
298                         else if ( minigame.minigame_flags & NMM_TURN_FLY )
299                         {
300                                 if ( tile.nmm_tile_piece && tile.nmm_tile_piece.team == e.team )
301                                 {
302                                         piece = tile.nmm_tile_piece;
303                                         entity tile2 = nmm_find_tile(minigame,argv(2));
304                                         if ( tile2 && !tile2.nmm_tile_piece )
305                                         {
306                                                 tile.nmm_tile_piece = world;
307                                                 tile2.nmm_tile_piece = piece;
308                                                 piece.origin = tile2.origin;
309                                                 piece.SendFlags |= MINIG_SF_UPDATE;
310                                                 tile = tile2;
311                                                 move_ok = 1;
312                                         }
313                                 }
314                                 
315                         }
316                         else if ( minigame.minigame_flags & NMM_TURN_TAKE )
317                         {
318                                 piece = tile.nmm_tile_piece;
319                                 if ( piece && piece.nmm_tile_piece.team != e.team )
320                                 {
321                                         tile.nmm_tile_piece = world;
322                                         piece.minigame_flags = NMM_PIECE_DEAD;
323                                         piece.SendFlags |= MINIG_SF_UPDATE;
324                                         move_ok = 1;
325                                 }
326                         }
327                         
328                         float nextteam = e.team % 2 + 1;
329                         float npieces = nmm_count_pieces(minigame,nextteam,NMM_PIECE_HOME|NMM_PIECE_BOARD);
330                         
331                         if ( npieces < 3 )
332                         {
333                                 minigame.minigame_flags = NMM_TURN_WIN | e.team;
334                                 minigame.SendFlags |= MINIG_SF_UPDATE;
335                         }
336                         else if ( move_ok)
337                         {
338                                 if ( !(minigame.minigame_flags & NMM_TURN_TAKE) && nmm_in_mill(tile) )
339                                 {
340                                         minigame.minigame_flags = NMM_TURN_TAKE|e.team;
341                                         float takemill = NMM_TURN_TAKEANY;
342                                         entity f = world;
343                                         while ( ( f = findentity(f,owner,minigame) ) )
344                                                 if ( f.classname == "minigame_nmm_tile" && f.nmm_tile_piece  &&
345                                                                 f.nmm_tile_piece.team == nextteam && !nmm_in_mill(f) )
346                                                 {
347                                                         takemill = 0;
348                                                         break;
349                                                 }
350                                         minigame.minigame_flags |= takemill;
351                                 }
352                                 else
353                                 {
354                                         if ( nmm_find_piece(world,minigame,nextteam,NMM_PIECE_HOME) )
355                                                 minigame.minigame_flags = NMM_TURN_PLACE|nextteam;
356                                         else if ( npieces == 3 )
357                                                 minigame.minigame_flags = NMM_TURN_FLY|nextteam;
358                                         else
359                                         {
360                                                 minigame.minigame_flags = NMM_TURN_WIN|e.team;
361                                                 entity f = world;
362                                                 while ( ( f = findentity(f,owner,minigame) ) )
363                                                         if ( f.classname == "minigame_nmm_tile" && f.nmm_tile_piece  &&
364                                                                 f.nmm_tile_piece.team == nextteam && nmm_tile_canmove(f) )
365                                                         {
366                                                                 minigame.minigame_flags = NMM_TURN_MOVE|nextteam;
367                                                                 break;
368                                                         }
369                                         }
370                                 }
371                                 minigame.SendFlags |= MINIG_SF_UPDATE;
372                         }
373                         else
374                                 dprint("Invalid move: ",...(2,string),"\n");
375                         return 1;
376                 }
377         }
378         return 0;
379 }
380
381 #elif defined(CSQC)
382
383 entity nmm_currtile;
384 entity nmm_fromtile;
385
386 vector nmm_boardpos;
387 vector nmm_boardsize;
388
389 // whether the given tile is a valid selection
390 float nmm_valid_selection(entity tile)
391 {
392         if ( ( tile.owner.minigame_flags & NMM_TURN_TEAM ) != minigame_self.team )
393                 return 0; // not our turn
394         if ( tile.owner.minigame_flags & NMM_TURN_PLACE )
395                 return !tile.nmm_tile_piece; // need to put a piece on an empty spot
396         if ( tile.owner.minigame_flags & NMM_TURN_MOVE )
397         {
398                 if ( tile.nmm_tile_piece && tile.nmm_tile_piece.team == minigame_self.team &&
399                                 nmm_tile_canmove(tile) )
400                         return 1; //  movable tile
401                 if ( nmm_fromtile ) // valid destination
402                         return !tile.nmm_tile_piece && nmm_tile_adjacent(nmm_fromtile,tile);
403                 return 0;
404         }
405         if ( tile.owner.minigame_flags & NMM_TURN_FLY )
406         {
407                 if ( nmm_fromtile )
408                         return !tile.nmm_tile_piece;
409                 else
410                         return tile.nmm_tile_piece && tile.nmm_tile_piece.team == minigame_self.team;
411         }
412         if ( tile.owner.minigame_flags & NMM_TURN_TAKE )
413                 return tile.nmm_tile_piece && tile.nmm_tile_piece.team != minigame_self.team &&
414                         ( (tile.owner.minigame_flags & NMM_TURN_TAKEANY) || !nmm_in_mill(tile) );
415         return 0;
416 }
417
418 // whether it should highlight valid tile selections
419 float nmm_draw_avaliable(entity tile)
420 {
421         if ( ( tile.owner.minigame_flags & NMM_TURN_TEAM ) != minigame_self.team )
422                 return 0;
423         if ( (tile.owner.minigame_flags & NMM_TURN_TAKE) )
424                 return 1;
425         if ( (tile.owner.minigame_flags & (NMM_TURN_FLY|NMM_TURN_MOVE)) && nmm_fromtile )
426                 return !tile.nmm_tile_piece;
427         return 0;
428 }
429
430 // Required function, draw the game board
431 void minigame_hud_board_nmm(vector pos, vector mySize)
432 {
433         minigame_hud_fitsqare(pos, mySize);
434         nmm_boardpos = pos;
435         nmm_boardsize = mySize;
436         minigame_hud_simpleboard(pos,mySize,minigame_texture("nmm/board"));
437         
438         vector tile_size = minigame_hud_denormalize_size('1 1 0'/7,pos,mySize);
439         vector tile_pos;
440         entity e;
441         FOREACH_MINIGAME_ENTITY(e)
442         {
443                 if ( e.classname == "minigame_nmm_tile" )
444                 {
445                         tile_pos = minigame_hud_denormalize(e.origin,pos,mySize);
446                         
447                         if ( e == nmm_fromtile )
448                         {
449                                 minigame_drawpic_centered( tile_pos, minigame_texture("nmm/tile_active"),
450                                         tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
451                         }
452                         else if ( nmm_draw_avaliable(e) && nmm_valid_selection(e) )
453                         {
454                                 minigame_drawpic_centered( tile_pos, minigame_texture("nmm/tile_available"),
455                                         tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
456                         }
457                         
458                         if ( e == nmm_currtile )
459                         {
460                                 minigame_drawpic_centered( tile_pos, minigame_texture("nmm/tile_selected"),
461                                         tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_ADDITIVE );
462                         }
463                         
464                         if ( e.nmm_tile_piece )
465                         {
466                                 minigame_drawpic_centered( tile_pos,  
467                                         minigame_texture(strcat("nmm/piece",ftos(e.nmm_tile_piece.team))),
468                                         tile_size*0.8, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
469                         }
470                         
471                         //drawstring(tile_pos, e.netname, hud_fontsize, '1 0 0', 1, DRAWFLAG_NORMAL);
472                 }
473         }
474         
475         if ( active_minigame.minigame_flags & NMM_TURN_WIN )
476         {
477                 vector winfs = hud_fontsize*2;
478                 string playername = "";
479                 FOREACH_MINIGAME_ENTITY(e)
480                         if ( e.classname == "minigame_player" && 
481                                         e.team == (active_minigame.minigame_flags & NMM_TURN_TEAM) )
482                                 playername = GetPlayerName(e.minigame_playerslot-1);
483                 
484                 vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
485                 vector win_sz;
486                 win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
487                         sprintf("%s^7 won the game!",playername), 
488                         winfs, 0, DRAWFLAG_NORMAL, 0.5);
489                 
490                 drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
491                 
492                 minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
493                         sprintf("%s^7 won the game!",playername), 
494                         winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
495         }
496 }
497
498 // Required function, draw the game status panel
499 void minigame_hud_status_nmm(vector pos, vector mySize)
500 {
501         HUD_Panel_DrawBg(1);
502         vector ts;
503         
504         ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
505                 hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
506         pos_y += ts_y;
507         mySize_y -= ts_y;
508         
509         vector player_fontsize = hud_fontsize * 1.75;
510         ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
511         ts_x = mySize_x;
512         
513         float player1x = 0;
514         float player2x = 0;
515         vector piece_sz = '48 48 0';
516         float piece_space = piece_sz_x + ( ts_x - 7 * piece_sz_x ) / 6;
517         vector mypos;
518         float piece_light = 1;
519         entity e = world;
520         
521         mypos = pos;
522         if ( (active_minigame.minigame_flags&NMM_TURN_TEAM) == 2 )
523                 mypos_y  += player_fontsize_y + ts_y;
524         drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
525         mypos_y += player_fontsize_y;
526         drawfill(mypos,eX*mySize_x+eY*piece_sz_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
527         
528         FOREACH_MINIGAME_ENTITY(e)
529         {
530                 if ( e.classname == "minigame_player" )
531                 {
532                         mypos = pos;
533                         if ( e.team == 2 )
534                                 mypos_y  += player_fontsize_y + ts_y;
535                         minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
536                                 GetPlayerName(e.minigame_playerslot-1),
537                                 player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
538                 }
539                 else if ( e.classname == "minigame_board_piece" )
540                 {
541                         mypos = pos;
542                         mypos_y += player_fontsize_y;
543                         if ( e.team == 2 )
544                         {
545                                 mypos_x += player2x;
546                                 player2x += piece_space;
547                                 mypos_y  += player_fontsize_y + ts_y;
548                         }
549                         else
550                         {
551                                 mypos_x += player1x;
552                                 player1x += piece_space;
553                         }
554                         if ( e.minigame_flags == NMM_PIECE_HOME )
555                                 piece_light = 0.5;
556                         else if ( e.minigame_flags == NMM_PIECE_BOARD )
557                                 piece_light = 1;
558                         else
559                                 piece_light = 0.15;
560                         
561                         drawpic(mypos, minigame_texture(strcat("nmm/piece",ftos(e.team))), piece_sz,
562                                 '1 1 1'*piece_light, panel_fg_alpha, DRAWFLAG_NORMAL );
563                 }
564         }
565 }
566
567 // Make the correct move
568 void nmm_make_move(entity minigame)
569 {
570         if ( nmm_currtile )
571         {
572                 if ( minigame.minigame_flags & (NMM_TURN_PLACE|NMM_TURN_TAKE) )
573                 {
574                         minigame_cmd("move ",nmm_currtile.netname);
575                         nmm_fromtile = world;
576                 }
577                 else if ( (minigame.minigame_flags & (NMM_TURN_MOVE|NMM_TURN_FLY)) )
578                 {
579                         if ( nmm_fromtile == nmm_currtile )
580                         {
581                                 nmm_fromtile = world;
582                         }
583                         else if ( nmm_currtile.nmm_tile_piece && nmm_currtile.nmm_tile_piece.team == minigame_self.team )
584                         {
585                                 nmm_fromtile = nmm_currtile;
586                         }
587                         else if ( nmm_fromtile )
588                         {
589                                 minigame_cmd("move ",nmm_fromtile.netname," ",nmm_currtile.netname);
590                                 nmm_fromtile = world;
591                         }
592                 }
593         }
594         else
595                 nmm_fromtile = world;
596 }
597
598 string nmm_turn_to_string(float turnflags)
599 {
600         if ( turnflags & NMM_TURN_WIN )
601         {
602                 if ( (turnflags&NMM_TURN_TEAM) != minigame_self.team )
603                         return _("You lost the game!");
604                 return _("You win!");
605         }
606         
607         if ( (turnflags&NMM_TURN_TEAM) != minigame_self.team )
608                 return _("Wait for your opponent to make their move");
609         if ( turnflags & NMM_TURN_PLACE )
610                 return _("Click on the game board to place your piece");
611         if ( turnflags & NMM_TURN_MOVE )
612                 return _("You can select one of your pieces to move it in one of the surrounding places");
613         if ( turnflags & NMM_TURN_FLY )
614                 return _("You can select one of your pieces to move it anywhere on the board");
615         if ( turnflags & NMM_TURN_TAKE )
616                 return _("You can take one of the opponent's pieces");
617         
618         return "";
619 }
620
621 // Required function, handle client events
622 float minigame_event_nmm(entity minigame, string event, ...)
623 {
624         if ( event == "activate" )
625         {
626                 nmm_fromtile = world;
627                 nmm_init_tiles(minigame);
628                 minigame.message = nmm_turn_to_string(minigame.minigame_flags);
629         }
630         else if ( event == "deactivate" )
631         {
632                 nmm_fromtile = world;
633                 nmm_kill_tiles(minigame);
634         }
635         else if ( event == "key_pressed" && (minigame.minigame_flags&NMM_TURN_TEAM) == minigame_self.team )
636         {
637                 switch ( ...(0,float) )
638                 {
639                         case K_RIGHTARROW:
640                         case K_KP_RIGHTARROW:
641                                 if ( ! nmm_currtile )
642                                         nmm_currtile = nmm_find_tile(active_minigame,"a7");
643                                 else
644                                 {
645                                         string tileid = nmm_currtile.netname;
646                                         nmm_currtile = world; 
647                                         while ( !nmm_currtile )
648                                         {
649                                                 tileid = minigame_relative_tile(tileid,1,0,7,7);
650                                                 nmm_currtile = nmm_find_tile(active_minigame,tileid);
651                                         }
652                                 }
653                                 return 1;
654                         case K_LEFTARROW:
655                         case K_KP_LEFTARROW:
656                                 if ( ! nmm_currtile )
657                                         nmm_currtile = nmm_find_tile(active_minigame,"g7");
658                                 else
659                                 {
660                                         string tileid = nmm_currtile.netname;
661                                         nmm_currtile = world; 
662                                         while ( !nmm_currtile )
663                                         {
664                                                 tileid = minigame_relative_tile(tileid,-1,0,7,7);
665                                                 nmm_currtile = nmm_find_tile(active_minigame,tileid);
666                                         }
667                                 }
668                                 return 1;
669                         case K_UPARROW:
670                         case K_KP_UPARROW:
671                                 if ( ! nmm_currtile )
672                                         nmm_currtile = nmm_find_tile(active_minigame,"a1");
673                                 else
674                                 {
675                                         string tileid = nmm_currtile.netname;
676                                         nmm_currtile = world; 
677                                         while ( !nmm_currtile )
678                                         {
679                                                 tileid = minigame_relative_tile(tileid,0,1,7,7);
680                                                 nmm_currtile = nmm_find_tile(active_minigame,tileid);
681                                         }
682                                 }
683                                 return 1;
684                         case K_DOWNARROW:
685                         case K_KP_DOWNARROW:
686                                 if ( ! nmm_currtile )
687                                         nmm_currtile = nmm_find_tile(active_minigame,"a7");
688                                 else
689                                 {
690                                         string tileid = nmm_currtile.netname;
691                                         nmm_currtile = world; 
692                                         while ( !nmm_currtile )
693                                         {
694                                                 tileid = minigame_relative_tile(tileid,0,-1,7,7);
695                                                 nmm_currtile = nmm_find_tile(active_minigame,tileid);
696                                         }
697                                 }
698                                 return 1;
699                         case K_ENTER:
700                         case K_KP_ENTER:
701                         case K_SPACE:
702                                 nmm_make_move(minigame);
703                                 return 1;
704                 }
705                 return 0;
706         }
707         else if ( event == "mouse_pressed" && ...(0,float) == K_MOUSE1 )
708         {
709                 nmm_make_move(minigame);
710                 return 1;
711         }
712         else if ( event == "mouse_moved" )
713         {
714                 nmm_currtile = world;
715                 vector tile_pos;
716                 vector tile_size = minigame_hud_denormalize_size('1 1 0'/7,nmm_boardpos,nmm_boardsize);
717                 entity e;
718                 FOREACH_MINIGAME_ENTITY(e)
719                 {
720                         if ( e.classname == "minigame_nmm_tile" )
721                         {
722                                 tile_pos = minigame_hud_denormalize(e.origin,nmm_boardpos,nmm_boardsize)-tile_size/2;
723                                 if ( minigame_hud_mouse_in(tile_pos, tile_size) && nmm_valid_selection(e) )
724                                 {
725                                         nmm_currtile = e;
726                                         break;
727                                 }
728                         }
729                 }
730                 return 1;
731         }
732         else if ( event == "network_receive" )
733         {
734                 if ( self.classname == "minigame_board_piece" && ( ...(1,float) & MINIG_SF_UPDATE ) )
735                 {
736                         entity e;
737                         string tileid = "";
738                         if ( self.minigame_flags & NMM_PIECE_BOARD )
739                                 tileid = minigame_tile_name(self.origin,7,7);
740                         FOREACH_MINIGAME_ENTITY(e)
741                         {
742                                 if ( e.classname == "minigame_nmm_tile" )
743                                 {
744                                         if ( e.nmm_tile_piece == self )
745                                                 e.nmm_tile_piece = world;
746                                         if ( e.netname == tileid )
747                                                 e.nmm_tile_piece = self;
748                                 }
749                         }
750                 }
751                 else if ( self.classname == "minigame" && ( ...(1,float) & MINIG_SF_UPDATE ) ) 
752                 {
753                         self.message = nmm_turn_to_string(self.minigame_flags);
754                         if ( self.minigame_flags & minigame_self.team )
755                                 minigame_prompt();
756                 }
757         }
758         
759         return 0;
760 }
761
762 #endif