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