]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/minigames/minigame/bd.qc
d4e1eebe808dadac63517112520f1675460bbef1
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / minigames / minigame / bd.qc
1 #include "bd.qh"
2 REGISTER_MINIGAME(bd, "Bulldozer");
3
4 REGISTER_NET_LINKED(ENT_CLIENT_BD_CONTROLLER)
5
6 const int BD_TURN_MOVE  = 0x0100; // player must move the bulldozer
7 const int BD_TURN_WIN   = 0x0200; // victory
8 const int BD_TURN_LOSS  = 0x0400; // they did it?!
9 const int BD_TURN_EDIT  = 0x0800; // editing mode
10 const int BD_TURN_TYPE  = 0x0f00; // turn type mask
11
12 // send flags
13 const int BD_SF_PLAYERMOVES = MINIG_SF_CUSTOM;
14 const int BD_SF_UPDATE_SINGLE = MINIG_SF_CUSTOM<<1;
15 const int BD_SF_UPDATE_ALL = MINIG_SF_CUSTOM<<2;
16
17 // 240 tiles...
18 const int BD_LET_CNT = 20;
19 const int BD_NUM_CNT = 20;
20
21 const int BD_TILE_SIZE = 20;
22
23 const int BD_TEAMS = 1;
24
25 .int bd_dir;
26
27 .int bd_dirs[BD_NUM_CNT];
28
29 .int bd_moves;
30
31 .int bd_tilelet;
32
33 .string bd_levelname;
34 .string bd_nextlevel;
35
36 #ifdef SVQC
37 .bool bd_canedit;
38 .int bd_forceupdate;
39 #endif
40
41 .int bd_tiletypes[BD_NUM_CNT];
42
43 .int bd_tiletype;
44 const int BD_TILE_DOZER = 1;
45 const int BD_TILE_TARGET = 2;
46 const int BD_TILE_BOULDER = 3;
47 const int BD_TILE_BRICK1 = 4;
48 const int BD_TILE_BRICK2 = 5;
49 const int BD_TILE_BRICK3 = 6;
50 const int BD_TILE_BRICK4 = 7;
51 const int BD_TILE_BRICK5 = 8;
52 const int BD_TILE_BRICK6 = 9;
53 const int BD_TILE_BRICK7 = 10;
54 const int BD_TILE_BRICK8 = 11;
55 const int BD_TILE_LAST = 11;
56
57 const int BD_DIR_UP = 0;
58 const int BD_DIR_DN = 1;
59 const int BD_DIR_LF = 2;
60 const int BD_DIR_RT = 3;
61
62 #ifdef SVQC
63 string autocvar_sv_minigames_bulldozer_startlevel = "level1";
64 #endif
65
66 // find same game piece given its tile name
67 entity bd_find_piece(entity minig, string tile, bool check_target)
68 {
69         entity e = NULL;
70         while ( ( e = findentity(e,owner,minig) ) )
71                 if ( e.classname == "minigame_board_piece" && e.netname == tile && ((check_target) ? e.bd_tiletype == BD_TILE_TARGET : e.bd_tiletype != BD_TILE_TARGET) )
72                         return e;
73         return NULL;
74 }
75
76 entity bd_find_controller(entity minig, int letter)
77 {
78         entity e = NULL;
79         while ( ( e = findentity(e,owner,minig) ) )
80                 if ( e.classname == "bd_controller" && e.bd_tilelet == letter )
81                         return e;
82         return NULL;
83 }
84
85 // check if the tile name is valid (15x15 grid)
86 bool bd_valid_tile(string tile)
87 {
88         if ( !tile )
89                 return false;
90         int number = minigame_tile_number(tile);
91         int letter = minigame_tile_letter(tile);
92         return 0 <= number && number < BD_NUM_CNT && 0 <= letter && letter < BD_LET_CNT;
93 }
94
95 void bd_controller_update(entity controller, int number)
96 {
97 #ifdef SVQC
98         controller.bd_forceupdate = number;
99 #endif
100         minigame_server_sendflags(controller,BD_SF_UPDATE_SINGLE);
101 }
102
103 entity bd_find_dozer(entity minig)
104 {
105         entity e = NULL;
106         while ( ( e = findentity(e,owner,minig) ) )
107                 if ( e.classname == "minigame_board_piece" && e.bd_tiletype == BD_TILE_DOZER )
108                         return e;
109         return NULL;
110 }
111
112 #ifdef SVQC
113 bool bd_controller_send(entity this, entity to, int sf)
114 {
115         WriteHeader(MSG_ENTITY, ENT_CLIENT_BD_CONTROLLER);
116         if(sf & BD_SF_UPDATE_ALL)
117                 sf &= ~BD_SF_UPDATE_SINGLE;
118
119         WriteByte(MSG_ENTITY, sf);
120         WriteByte(MSG_ENTITY, this.bd_tilelet);
121         WriteString(MSG_ENTITY,this.owner.netname);
122
123         if(sf & BD_SF_UPDATE_SINGLE)
124         {
125                 int number = this.bd_forceupdate;
126                 //this.bd_forceupdate = 0;
127                 int ttype = this.bd_tiletypes[number];
128                 int dir = this.bd_dirs[number];
129                 WriteByte(MSG_ENTITY, number);
130                 WriteByte(MSG_ENTITY, ttype);
131                 WriteByte(MSG_ENTITY, dir);
132         }
133
134         if(sf & BD_SF_UPDATE_ALL)
135         {
136                 for(int j = 0; j < BD_NUM_CNT; ++j)
137                 {
138                         int ttype = this.bd_tiletypes[j];
139                         int dir = this.bd_dirs[j];
140                         WriteByte(MSG_ENTITY, ttype);
141                         WriteByte(MSG_ENTITY, dir);
142                 }
143         }
144
145         return true;
146 }
147 #elif defined(CSQC)
148 void minigame_read_owner(entity this);
149
150 NET_HANDLE(ENT_CLIENT_BD_CONTROLLER, bool isNew)
151 {
152         this.classname = "bd_controller";
153         return = true;
154
155         int sf = ReadByte();
156         this.bd_tilelet = ReadByte();
157         minigame_read_owner(this);
158
159         if(sf & BD_SF_UPDATE_SINGLE)
160         {
161                 int number = ReadByte();
162                 this.bd_tiletypes[number] = ReadByte();
163                 this.bd_dirs[number] = ReadByte();
164         }
165
166         if(sf & BD_SF_UPDATE_ALL)
167         {
168                 for(int j = 0; j < BD_NUM_CNT; ++j)
169                 {
170                         this.bd_tiletypes[j] = ReadByte();
171                         this.bd_dirs[j] = ReadByte();
172                 }
173         }
174 }
175 #endif
176
177 void bd_check_winner(entity minig)
178 {
179         int total = 0, valid = 0;
180         entity e = NULL;
181         while ( ( e = findentity(e,owner,minig) ) )
182                 if ( e.classname == "minigame_board_piece" && e.bd_tiletype == BD_TILE_TARGET )
183                 {
184                         ++total;
185                         if(bd_find_piece(minig, e.netname, false).bd_tiletype == BD_TILE_BOULDER)
186                                 ++valid;
187                 }
188
189         if(valid >= total)
190         {
191                 minig.minigame_flags = BD_TURN_WIN;
192                 minigame_server_sendflags(minig,MINIG_SF_UPDATE);
193         }
194 }
195
196 vector bd_get_dir(int bdir)
197 {
198         switch(bdir)
199         {
200                 case BD_DIR_UP: return '0 1 0'; // up
201                 default:
202                 case BD_DIR_DN: return '0 -1 0'; // down
203                 case BD_DIR_LF: return '-1 0 0'; // left
204                 case BD_DIR_RT: return '1 0 0'; // right
205         }
206 }
207
208 string bd_get_dir_name(int bdir)
209 {
210         switch(bdir)
211         {
212                 case BD_DIR_UP: return "u"; // up
213                 default:
214                 case BD_DIR_DN: return "d"; // down
215                 case BD_DIR_LF: return "l"; // left
216                 case BD_DIR_RT: return "r"; // right
217         }
218 }
219
220 int bd_dir_fromname(string bdir)
221 {
222         if(bdir == "up" || bdir == "u")
223                 return BD_DIR_UP; // up
224         if(bdir == "down" || bdir == "dn" || bdir == "d")
225                 return BD_DIR_DN; /// down
226         if(bdir == "left" || bdir == "lt" || bdir == "l")
227                 return BD_DIR_LF; // left
228         if(bdir == "right" || bdir == "rt" || bdir == "r")
229                 return BD_DIR_RT; // right
230
231         return BD_DIR_DN; // down
232 }
233
234 bool bd_canfill(int ttype)
235 {
236         switch(ttype)
237         {
238                 case BD_TILE_BRICK8:
239                 case BD_TILE_BRICK7:
240                 case BD_TILE_BRICK6:
241                 case BD_TILE_BRICK5:
242                 case BD_TILE_BRICK4:
243                 case BD_TILE_BRICK3:
244                 case BD_TILE_BRICK2:
245                 case BD_TILE_BRICK1: return true;
246         }
247
248         return false;
249 }
250
251 bool bd_move_dozer(entity minigame, entity dozer)
252 {
253         //if(!dozer.bd_dir)
254                 //return false; // nope!
255
256         int myx = minigame_tile_letter(dozer.netname);
257         int myy = minigame_tile_number(dozer.netname);
258
259         vector dir = bd_get_dir(dozer.bd_dir);
260
261         myx += dir.x;
262         myy += dir.y;
263
264         string newpos = minigame_tile_buildname(myx, myy);
265         if(!bd_valid_tile(newpos))
266                 return false;
267
268         entity hit = bd_find_piece(minigame, newpos, false);
269
270         if(hit)
271         switch(hit.bd_tiletype)
272         {
273                 case BD_TILE_DOZER: // wtf, but let's do this incase
274                 case BD_TILE_BRICK8:
275                 case BD_TILE_BRICK7:
276                 case BD_TILE_BRICK6:
277                 case BD_TILE_BRICK5:
278                 case BD_TILE_BRICK4:
279                 case BD_TILE_BRICK3:
280                 case BD_TILE_BRICK2:
281                 case BD_TILE_BRICK1: return false;
282                 case BD_TILE_BOULDER:
283                 {
284                         string testpos;
285                         int tx = minigame_tile_letter(hit.netname);
286                         int ty = minigame_tile_number(hit.netname);
287
288                         tx += dir.x;
289                         ty += dir.y;
290
291                         testpos = minigame_tile_buildname(tx, ty);
292                         entity testhit = bd_find_piece(minigame, testpos, false);
293
294                         if(!bd_valid_tile(testpos) || testhit)
295                                 return false;
296
297                         if(hit.netname) { strunzone(hit.netname); }
298                         hit.netname = strzone(testpos);
299                         minigame_server_sendflags(hit,MINIG_SF_UPDATE);
300                         break;
301                 }
302         }
303
304         entity controller = bd_find_controller(minigame, minigame_tile_letter(newpos));
305         int number = minigame_tile_number(newpos);
306         switch(controller.bd_tiletypes[number])
307         {
308                 case BD_TILE_BRICK8:
309                 case BD_TILE_BRICK7:
310                 case BD_TILE_BRICK6:
311                 case BD_TILE_BRICK5:
312                 case BD_TILE_BRICK4:
313                 case BD_TILE_BRICK3:
314                 case BD_TILE_BRICK2:
315                 case BD_TILE_BRICK1: return false;
316         }
317
318         if(dozer.netname) { strunzone(dozer.netname); }
319         dozer.netname = strzone(newpos);
320
321         return true;
322 }
323
324 // make a move
325 void bd_move(entity minigame, entity player, string dir)
326 {
327         if ( minigame.minigame_flags & BD_TURN_MOVE )
328         if ( dir )
329         {
330                 //if ( bd_valid_tile(pos) )
331                 //if ( bd_find_piece(minigame, pos, false) )
332                 {
333                         entity dozer = bd_find_dozer(minigame);
334                         if(!dozer)
335                         {
336                                 LOG_INFO("Dozer wasn't found!\n");
337                                 return; // should not happen... TODO: end match?
338                         }
339
340                         string thedir = strtolower(dir);
341                         int bdir = bd_dir_fromname(thedir);
342
343                         int moved = 0;
344                         entity e = NULL;
345                         while ( ( e = findentity(e,owner,minigame) ) )
346                                 if ( e.classname == "minigame_board_piece" && e.bd_tiletype == BD_TILE_DOZER )
347                                 {
348                                         e.bd_dir = bdir;
349
350                                         if(bd_move_dozer(minigame, e))
351                                                 ++moved;
352
353                                         minigame_server_sendflags(e,MINIG_SF_UPDATE); // update anyway
354                                 }
355
356                         if(moved)
357                                 player.bd_moves++;
358
359                         bd_check_winner(minigame);
360
361                         minigame_server_sendflags(player,BD_SF_PLAYERMOVES);
362                         minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
363                 }
364         }
365 }
366
367 // editor
368 void bd_editor_place(entity minigame, entity player, string pos, int thetile, string thedir)
369 {
370         if ( minigame.minigame_flags & BD_TURN_EDIT )
371         if ( pos && thetile )
372         {
373                 if ( bd_valid_tile(pos) )
374                 {
375                         entity found_piece = bd_find_piece(minigame, pos, false);
376                         entity targ = bd_find_piece(minigame, pos, true);
377
378                         if(found_piece.bd_tiletype == BD_TILE_DOZER && thedir != "")
379                         {
380                                 string newdir = strtolower(thedir);
381                                 int bdir = bd_dir_fromname(newdir);
382
383                                 found_piece.bd_dir = bdir;
384                                 minigame_server_sendflags(found_piece,MINIG_SF_UPDATE); // update anyway
385                                 return;
386                         }
387
388                         //entity dozer = bd_find_dozer(minigame);
389                         //if(dozer && thetile == BD_TILE_DOZER && pos != dozer.netname)
390                                 //return; // nice try
391
392                         int tlet = minigame_tile_letter(pos);
393                         int tnum = minigame_tile_number(pos);
394                         entity controller = bd_find_controller(minigame, tlet);
395                         if(controller.bd_tiletypes[tnum])
396                         {
397                                 controller.bd_tiletypes[tnum] = 0;
398                                 controller.bd_dirs[tnum] = 0;
399                                 bd_controller_update(controller, tnum);
400                                 return;
401                         }
402
403                         if(found_piece || (targ && thetile != BD_TILE_BOULDER))
404                         {
405                                 entity piece = bd_find_piece(minigame, pos, false);
406                                 if(!piece) piece = bd_find_piece(minigame, pos, true);
407                                 if(!piece)
408                                         return; // how?!
409
410                                 if(piece.netname) { strunzone(piece.netname); }
411                                 delete(piece);
412                                 minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
413                                 return;
414                         }
415
416                         if(bd_canfill(thetile))
417                         {
418                                 int number = minigame_tile_number(pos);
419                                 int letter = minigame_tile_letter(pos);
420                                 entity controller = bd_find_controller(minigame, letter);
421                                 controller.bd_tiletypes[number] = thetile;
422                                 controller.bd_dirs[number] = 0;
423                                 bd_controller_update(controller, number);
424                         }
425                         else
426                         {
427                                 entity piece = msle_spawn(minigame,"minigame_board_piece");
428                                 piece.team = 1;
429                                 piece.netname = strzone(pos);
430                                 piece.bd_tiletype = thetile;
431                                 piece.bd_dir = 0;
432                                 minigame_server_sendflags(piece,MINIG_SF_UPDATE);
433                         }
434
435                         minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
436                 }
437         }
438 }
439
440 void bd_do_move(entity minigame, entity player, string dir, string thetile, string thedir)
441 {
442         if(minigame.minigame_flags & BD_TURN_MOVE)
443                 bd_move(minigame, player, dir);
444
445         if(minigame.minigame_flags & BD_TURN_EDIT)
446                 bd_editor_place(minigame, player, dir, stof(thetile), thedir);
447 }
448
449 void bd_fill_recurse(entity minigame, entity player, int thetype, int letter, int number)
450 {
451         string pos = minigame_tile_buildname(letter,number);
452         if(!bd_valid_tile(pos))
453                 return;
454         if(bd_find_piece(minigame, pos, false) || bd_find_piece(minigame, pos, true))
455                 return;
456
457         bd_editor_place(minigame, player, pos, thetype, "");
458
459         bd_fill_recurse(minigame, player, thetype, letter - 1, number);
460         bd_fill_recurse(minigame, player, thetype, letter + 1, number);
461         bd_fill_recurse(minigame, player, thetype, letter, number - 1);
462         bd_fill_recurse(minigame, player, thetype, letter, number + 1);
463 }
464
465 void bd_unfill_recurse(entity minigame, entity player, int thetype, int letter, int number)
466 {
467         string pos = minigame_tile_buildname(letter,number);
468         if(!bd_valid_tile(pos))
469                 return;
470
471         entity targ = bd_find_piece(minigame, pos, true);
472         entity piece = bd_find_piece(minigame, pos, false);
473
474         if(targ && thetype == targ.bd_tiletype)
475         {
476                 if(targ.netname) { strunzone(targ.netname); }
477                 delete(targ);
478         }
479         else if(piece && thetype == piece.bd_tiletype)
480         {
481                 if(piece.netname) { strunzone(piece.netname); }
482                 delete(piece);
483         }
484         else return;
485
486         bd_unfill_recurse(minigame, player, thetype, letter - 1, number);
487         bd_unfill_recurse(minigame, player, thetype, letter + 1, number);
488         bd_unfill_recurse(minigame, player, thetype, letter, number - 1);
489         bd_unfill_recurse(minigame, player, thetype, letter, number + 1);
490 }
491
492 void bd_do_fill(entity minigame, entity player, string dir, string thetile)
493 {
494 #ifdef SVQC
495         if(!player.minigame_players.bd_canedit)
496         {
497                 sprint(player.minigame_players, "You're not allowed to edit levels, sorry!\n");
498                 return;
499         }
500 #endif
501
502         if(minigame.minigame_flags & BD_TURN_EDIT)
503         {
504                 int thetype = stof(thetile);
505
506                 entity targ = bd_find_piece(minigame, dir, true);
507                 entity piece = bd_find_piece(minigame, dir, false);
508
509                 if(!bd_canfill(thetype) || (piece || targ))
510                 {
511                         int killtype = 0;
512
513                         if(targ) { killtype = targ.bd_tiletype; }
514                         if(piece) { killtype = piece.bd_tiletype; }
515
516                         if(killtype)
517                         {
518                                 int letter = minigame_tile_letter(dir);
519                                 int number = minigame_tile_number(dir);
520                                 bd_unfill_recurse(minigame, player, killtype, letter, number);
521                         }
522
523                         return;
524                 }
525
526                 int letter = minigame_tile_letter(dir);
527                 int number = minigame_tile_number(dir);
528
529                 bd_fill_recurse(minigame, player, thetype, letter, number);
530         }
531 }
532
533 void bd_reset_moves(entity minigame)
534 {
535         entity e;
536 #ifdef SVQC
537         for(e = minigame.minigame_players; e; e = e.list_next)
538 #elif defined(CSQC)
539         e = NULL;
540         while( (e = findentity(e,owner,minigame)) )
541                 if ( e.classname == "minigame_player" )
542 #endif
543                 {
544                         e.bd_moves = 0;
545                         minigame_server_sendflags(e,BD_SF_PLAYERMOVES);
546                 }
547 }
548
549 void bd_load_level(entity minigame);
550 void bd_setup_pieces(entity minigame)
551 {
552         entity e = NULL;
553         while( (e = findentity(e, owner, minigame)) )
554                 if(e.classname == "minigame_board_piece")
555                 {
556                         if(e.netname) { strunzone(e.netname); }
557                         delete(e);
558                 }
559         e = NULL;
560         while( (e = findentity(e, owner, minigame)) )
561                 if(e.classname == "bd_controller")
562                 {
563                         delete(e);
564                 }
565
566         for(int letter = 0; letter < BD_LET_CNT; ++letter)
567         {
568                 entity controller = new_pure(bd_controller);
569                 controller.owner = minigame;
570                 controller.bd_tilelet = letter;
571         #ifdef SVQC
572                 Net_LinkEntity(controller, false, 0, bd_controller_send);
573         #endif
574         }
575
576         bd_load_level(minigame);
577 }
578
579 void bd_do_next_match(entity minigame, entity player)
580 {
581         minigame.minigame_flags = BD_TURN_MOVE;
582         minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
583
584         if(minigame.bd_nextlevel && minigame.bd_nextlevel != "")
585         {
586                 if(minigame.bd_levelname) { strunzone(minigame.bd_levelname); }
587                 minigame.bd_levelname = strzone(minigame.bd_nextlevel);
588         }
589
590         bd_setup_pieces(minigame);
591
592         bd_reset_moves(minigame);
593 }
594
595 void bd_set_next_match(entity minigame, string next)
596 {
597         if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
598         minigame.bd_nextlevel = strzone(next);
599 }
600
601 void bd_next_match(entity minigame, entity player, string next)
602 {
603         if(minigame.minigame_flags & BD_TURN_WIN)
604                 bd_do_next_match(minigame, player);
605         if(minigame.minigame_flags & BD_TURN_EDIT)
606                 bd_set_next_match(minigame, next);
607 }
608
609 // request a new match
610 void bd_restart_match(entity minigame, entity player)
611 {
612         minigame.minigame_flags = BD_TURN_MOVE;
613         minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
614
615         bd_setup_pieces(minigame);
616
617         bd_reset_moves(minigame);
618 }
619
620 void bd_activate_editor(entity minigame, entity player)
621 {
622 #ifdef SVQC
623         if(!player.minigame_players.bd_canedit)
624         {
625                 sprint(player.minigame_players, "You're not allowed to edit levels, sorry!\n");
626                 return;
627         }
628 #endif
629
630         minigame.minigame_flags = BD_TURN_EDIT;
631         minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
632
633         bd_reset_moves(minigame);
634
635         bd_setup_pieces(minigame);
636 }
637
638 string bd_save_controller_piece(entity minigame, entity e, int number)
639 {
640         string bd_string = "";
641
642         string tilename = minigame_tile_buildname(e.bd_tilelet, number);
643
644         bd_string = strcat(bd_string, "\"", tilename, "\" ");
645         bd_string = strcat(bd_string, ftos(e.bd_tiletypes[number]), " ");
646         bd_string = strcat(bd_string, ftos(e.bd_dirs[number]));
647
648         return bd_string;
649 }
650
651 string bd_save_piece(entity minigame, entity e)
652 {
653         string bd_string = "";
654
655         bd_string = strcat(bd_string, "\"", e.netname, "\" ");
656         bd_string = strcat(bd_string, ftos(e.bd_tiletype), " ");
657         bd_string = strcat(bd_string, ftos(e.bd_dir));
658
659         return bd_string;
660 }
661
662 void bd_set_nextlevel(entity minigame, string s)
663 {
664         tokenize_console(s);
665
666         if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
667         minigame.bd_nextlevel = strzone(argv(2));
668 }
669
670 int bd_fix_dir(vector dir)
671 {
672         if(dir.x == 0 && dir.y == 1) { return BD_DIR_UP; } // up
673         if(dir.x == 0 && dir.y == -1) { return BD_DIR_DN; } // down
674         if(dir.x == -1 && dir.y == 0) { return BD_DIR_LF; } // left
675         if(dir.x == 1 && dir.y == 0) { return BD_DIR_RT; } // right
676
677         return BD_DIR_DN; // down if all else fails
678 }
679
680 void bd_load_piece(entity minigame, string s)
681 {
682         // separate pieces between the ; symbols
683         string bd_string = s;
684
685         tokenize_console(bd_string);
686
687         int argv_num = 0;
688         string tilename = strzone(argv(argv_num)); ++argv_num;
689         int tiletype = stoi(argv(argv_num)); ++argv_num;
690         int dir = stoi(argv(argv_num)); ++argv_num;
691
692         if(bd_canfill(tiletype))
693         {
694                 int letter = minigame_tile_letter(tilename);
695                 int number = minigame_tile_number(tilename);
696                 entity controller = bd_find_controller(minigame, letter);
697                 controller.bd_tiletypes[number] = tiletype;
698                 controller.bd_dirs[number] = dir;
699
700                 bd_controller_update(controller, number);
701         }
702         else
703         {
704                 entity e = msle_spawn(minigame,"minigame_board_piece");
705                 e.netname = tilename;
706                 e.team = 1;
707                 e.bd_dir = dir;
708                 e.bd_tiletype = tiletype;
709                 minigame_server_sendflags(e,MINIG_SF_ALL);
710         }
711 }
712
713 bool bd_save_level(entity minigame)
714 {
715         if(minigame.bd_levelname && minigame.bd_levelname != "")
716         {
717                 int target_count = 0, boulder_count = 0;
718                 entity piece = NULL;
719                 while((piece = findentity(piece,owner,minigame)))
720                 if(piece.classname == "minigame_board_piece")
721                         if(piece.bd_tiletype == BD_TILE_BOULDER)
722                                 ++boulder_count;
723                         else if(piece.bd_tiletype == BD_TILE_TARGET)
724                                 ++target_count;
725
726                 if(boulder_count != target_count)
727                 {
728                         LOG_INFO("Not enough targets or boulders, fix your level!\n");
729                         return false;
730                 }
731
732                 // saves all objects to the database file
733                 string file_name;
734                 float file_get;
735
736                 file_name = strcat("minigames/bulldozer/storage_", minigame.bd_levelname, ".txt");
737                 file_get = fopen(file_name, FILE_WRITE);
738                 fputs(file_get, strcat("// bulldozer storage \"", minigame.bd_levelname, "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S"), "\n"));
739
740                 if(minigame.bd_nextlevel && minigame.bd_nextlevel != "" && fexists(strcat("minigames/bulldozer/storage_", minigame.bd_nextlevel, ".txt")))
741                         fputs(file_get, strcat("nextlevel = \"", minigame.bd_nextlevel, "\"\n"));
742
743                 entity e = NULL;
744                 while ( ( e = findentity(e,owner,minigame) ) )
745                 if ( e.classname == "bd_controller" )
746                 {
747                         for(int j = 0; j < BD_NUM_CNT; ++j)
748                         {
749                                 // use a line of text for each object, listing all properties
750                                 fputs(file_get, strcat(bd_save_controller_piece(minigame, e, j), "\n"));
751                         }
752                 }
753                 e = NULL;
754
755                 while ( ( e = findentity(e,owner,minigame) ) )
756                 if ( e.classname == "minigame_board_piece" )
757                 {
758                         // use a line of text for each object, listing all properties
759                         fputs(file_get, strcat(bd_save_piece(minigame, e), "\n"));
760                 }
761                 fclose(file_get);
762
763                 return true;
764         }
765
766         return false;
767 }
768
769 void bd_load_level(entity minigame)
770 {
771         // loads all items from the database file
772         string file_read, file_name;
773         float file_get;
774
775         file_name = strcat("minigames/bulldozer/storage_", minigame.bd_levelname, ".txt");
776         file_get = fopen(file_name, FILE_READ);
777         if(file_get < 0)
778         {
779                 LOG_INFO("^3BULLDOZER: ^7could not find storage file ^3", file_name, "^7, no items were loaded\n");
780         }
781         else
782         {
783                 for(;;)
784                 {
785                         file_read = fgets(file_get);
786                         if(file_read == "")
787                                 break;
788                         if(substring(file_read, 0, 2) == "//")
789                                 continue;
790                         if(substring(file_read, 0, 1) == "#")
791                                 continue;
792                         if(substring(file_read, 0, 9) == "nextlevel")
793                         {
794                                 bd_set_nextlevel(minigame, file_read);
795                                 continue;
796                         }
797
798                         bd_load_piece(minigame, file_read);
799                 }
800         }
801         fclose(file_get);
802 }
803
804 void bd_close_editor(entity minigame, entity player)
805 {
806 #ifdef SVQC
807         if(!player.minigame_players.bd_canedit)
808         {
809                 sprint(player.minigame_players, "You're not allowed to edit levels, sorry!\n");
810                 return;
811         }
812 #endif
813
814         entity dozer = bd_find_dozer(minigame);
815         if(!dozer)
816         {
817                 LOG_INFO("You need to place a bulldozer on the level to save it!\n");
818                 return;
819         }
820
821         if(bd_save_level(minigame))
822         {
823                 minigame.minigame_flags = BD_TURN_MOVE;
824                 minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
825         }
826         else
827         {
828                 LOG_INFO("You need to set the level name!\n");
829                 return;
830         }
831 }
832
833 #ifdef SVQC
834
835 // required function, handle server side events
836 int bd_server_event(entity minigame, string event, ...)
837 {
838         switch(event)
839         {
840                 case "start":
841                 {
842                         if(minigame.bd_levelname) { strunzone(minigame.bd_levelname); }
843                         minigame.bd_levelname = strzone(autocvar_sv_minigames_bulldozer_startlevel);
844                         bd_setup_pieces(minigame);
845                         minigame.minigame_flags = BD_TURN_MOVE;
846
847                         return true;
848                 }
849                 case "end":
850                 {
851                         entity e = NULL;
852                         while( (e = findentity(e, owner, minigame)) )
853                         if(e.classname == "minigame_board_piece")
854                         {
855                                 if(e.netname) { strunzone(e.netname); }
856                                 delete(e);
857                         }
858                         e = NULL;
859                         while( (e = findentity(e, owner, minigame)) )
860                         if(e.classname == "bd_controller")
861                         {
862                                 delete(e);
863                         }
864
865                         if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
866                         if(minigame.bd_levelname) { strunzone(minigame.bd_levelname); }
867                         return false;
868                 }
869                 case "join":
870                 {
871                         int pl_num = minigame_count_players(minigame);
872
873                         if(pl_num >= BD_TEAMS) { return false; }
874
875                         return 1;
876                 }
877                 case "cmd":
878                 {
879                         switch(argv(0))
880                         {
881                                 case "move":
882                                         bd_do_move(minigame, ...(0,entity), ((...(1,int)) >= 2 ? argv(1) : string_null), ((...(1,int)) >= 3 ? argv(2) : string_null), ((...(1,int)) >= 4 ? argv(3) : string_null));
883                                         return true;
884                                 case "next":
885                                         bd_next_match(minigame,...(0,entity), ((...(1,int) >= 2 ? argv(1) : string_null)));
886                                         return true;
887                                 case "restart":
888                                         bd_restart_match(minigame,...(0,entity));
889                                         return true;
890                                 case "edit":
891                                         bd_activate_editor(minigame,...(0,entity));
892                                         return true;
893                                 case "save":
894                                         bd_close_editor(minigame,...(0,entity));
895                                         return true;
896                                 case "fill":
897                                         bd_do_fill(minigame, ...(0,entity), ((...(1,int)) >= 2 ? argv(1) : string_null), ((...(1,int)) >= 3 ? argv(2) : string_null));
898                                         return true;
899                         }
900
901                         return false;
902                 }
903                 case "network_send":
904                 {
905                         entity sent = ...(0,entity);
906                         int sf = ...(1,int);
907                         if ( sent.classname == "minigame_board_piece" && (sf & MINIG_SF_UPDATE) )
908                         {
909                                 int letter = minigame_tile_letter(sent.netname);
910                                 int number = minigame_tile_number(sent.netname);
911
912                                 WriteByte(MSG_ENTITY,letter);
913                                 WriteByte(MSG_ENTITY,number);
914
915                                 WriteByte(MSG_ENTITY,sent.bd_tiletype);
916
917                                 WriteByte(MSG_ENTITY,sent.bd_dir);
918                         }
919                         else if(sent.classname == "minigame_player" && (sf & BD_SF_PLAYERMOVES))
920                                 WriteShort(MSG_ENTITY,sent.bd_moves);
921                         return false;
922                 }
923         }
924
925         return false;
926 }
927
928
929 #elif defined(CSQC)
930
931 int bd_curr_tile;
932 string bd_curr_pos;
933
934 .entity bd_enemy;
935 .bool bd_hide;
936
937 vector bd_boardpos; // HUD board position
938 vector bd_boardsize;// HUD board size
939
940 string bd_get_tile_pic(int tileid)
941 {
942         switch(tileid)
943         {
944                 case BD_TILE_BOULDER: return "bd/boulder";
945                 case BD_TILE_BRICK1: return "bd/brick1";
946                 case BD_TILE_BRICK2: return "bd/brick2";
947                 case BD_TILE_BRICK3: return "bd/brick3";
948                 case BD_TILE_BRICK4: return "bd/brick4";
949                 case BD_TILE_BRICK5: return "bd/brick5";
950                 case BD_TILE_BRICK6: return "bd/brick6";
951                 case BD_TILE_BRICK7: return "bd/brick7";
952                 case BD_TILE_BRICK8: return "bd/brick8";
953                 case BD_TILE_TARGET: return "bd/target";
954                 case BD_TILE_DOZER: return "bd/dozer";
955         }
956
957         return string_null;
958 }
959
960 // Required function, draw the game board
961 void bd_hud_board(vector pos, vector mySize)
962 {
963         minigame_hud_fitsqare(pos, mySize);
964         bd_boardpos = pos;
965         bd_boardsize = mySize;
966
967         minigame_hud_simpleboard(pos,mySize,minigame_texture("bd/board"));
968
969         vector tile_size = minigame_hud_denormalize_size('1 1 0' / BD_TILE_SIZE,pos,mySize);
970         vector tile_pos;
971
972         entity e;
973         FOREACH_MINIGAME_ENTITY(e)
974         {
975                 if(e.classname == "minigame_board_piece")
976                 {
977                         if(e.bd_tiletype == BD_TILE_TARGET)
978                         {
979                                 e.bd_enemy = NULL;
980                                 e.bd_enemy = bd_find_piece(active_minigame, e.netname, false);
981                         }
982                         else if(e.bd_tiletype == BD_TILE_BOULDER)
983                         {
984                                 e.bd_hide = false; // reset either way
985                                 e.bd_hide = ((bd_find_piece(active_minigame, e.netname, true)) != NULL);
986                         }
987                 }
988         }
989         FOREACH_MINIGAME_ENTITY(e)
990         {
991                 if ( e.classname == "bd_controller" )
992                 {
993                         for(int j = 0; j < BD_NUM_CNT; ++j)
994                         {
995                                 if(!e.bd_tiletypes[j]) continue;
996
997                                 int letter = e.bd_tilelet;
998                                 string mypos = minigame_tile_buildname(letter, j);
999
1000                                 tile_pos = minigame_tile_pos(mypos,BD_NUM_CNT,BD_LET_CNT);
1001                                 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1002
1003                                 string thepiece = bd_get_tile_pic(e.bd_tiletypes[j]);
1004
1005                                 minigame_drawpic_centered( tile_pos,
1006                                                 minigame_texture(thepiece),
1007                                                 tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
1008                         }       
1009                 }
1010                 else if ( e.classname == "minigame_board_piece" )
1011                 {
1012                         if(e.bd_tiletype != BD_TILE_DOZER && !e.bd_hide) // hide boulders
1013                         {
1014                                 tile_pos = minigame_tile_pos(e.netname,BD_NUM_CNT,BD_LET_CNT);
1015                                 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1016
1017                                 string thepiece = bd_get_tile_pic(e.bd_tiletype);
1018
1019                                 if(e.bd_enemy)
1020                                         thepiece = "bd/boulder_target";
1021
1022                                 minigame_drawpic_centered( tile_pos,
1023                                                 minigame_texture(thepiece),
1024                                                 tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
1025                         }
1026                 }
1027         }
1028
1029         // draw dozers on top, always
1030         FOREACH_MINIGAME_ENTITY(e)
1031         {
1032                 if ( e.classname == "minigame_board_piece" && e.bd_tiletype == BD_TILE_DOZER )
1033                 {
1034                         tile_pos = minigame_tile_pos(e.netname,BD_NUM_CNT,BD_LET_CNT);
1035                         tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1036
1037                         int bdir = e.bd_dir;
1038                         float theang = 0;
1039
1040                         switch(bdir)
1041                         {
1042                                 case BD_DIR_UP: theang = 0; break;
1043                                 default:
1044                                 case BD_DIR_DN: theang = M_PI; break;
1045                                 case BD_DIR_LF: theang = M_PI * 3 / 2; break;
1046                                 case BD_DIR_RT: theang = M_PI / 2; break; 
1047                         }
1048
1049                         drawrotpic(tile_pos, theang, minigame_texture("bd/dozer"),
1050                                                 tile_size, tile_size/2, '1 1 1',
1051                                                 panel_fg_alpha, DRAWFLAG_NORMAL );
1052                 }
1053         }
1054
1055         if(active_minigame.minigame_flags & BD_TURN_EDIT)
1056         if(bd_valid_tile(bd_curr_pos))
1057         {
1058                 entity piece = bd_find_piece(active_minigame, bd_curr_pos, false);
1059                 entity targ = bd_find_piece(active_minigame, bd_curr_pos, true);
1060                 string thepiece = ((piece || (targ && bd_curr_tile != BD_TILE_BOULDER)) ? "bd/delete" : bd_get_tile_pic(bd_curr_tile));
1061
1062                 tile_pos = minigame_tile_pos(bd_curr_pos,BD_LET_CNT,BD_NUM_CNT);
1063                 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1064                 if(bd_curr_tile == BD_TILE_DOZER)
1065                 {
1066                         drawrotpic(tile_pos, M_PI, minigame_texture("bd/dozer"),
1067                                                 tile_size, tile_size/2, '1 1 1',
1068                                                 panel_fg_alpha/2, DRAWFLAG_NORMAL );
1069                 }
1070                 else
1071                 {
1072                         minigame_drawpic_centered( tile_pos,
1073                                         minigame_texture(thepiece),
1074                                         tile_size, '1 1 1', panel_fg_alpha/2, DRAWFLAG_NORMAL );
1075                 }
1076         }
1077
1078         if ( (active_minigame.minigame_flags & BD_TURN_LOSS) || (active_minigame.minigame_flags & BD_TURN_WIN) )
1079         {
1080                 vector winfs = hud_fontsize*2;
1081                 string victory_text = "Game over!";
1082
1083                 if(active_minigame.minigame_flags & BD_TURN_WIN)
1084                         victory_text = "Well done! Click 'Next Level' to continue";
1085
1086                 vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
1087                 vector win_sz;
1088                 win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
1089                         sprintf("%s", victory_text),
1090                         winfs, 0, DRAWFLAG_NORMAL, 0.5);
1091
1092                 drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'0.3 0.3 1',0.8,DRAWFLAG_ADDITIVE);
1093
1094                 minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
1095                         sprintf("%s", victory_text),
1096                         winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
1097         }
1098 }
1099
1100
1101 // Required function, draw the game status panel
1102 void bd_hud_status(vector pos, vector mySize)
1103 {
1104         HUD_Panel_DrawBg();
1105         vector ts;
1106         ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
1107                 hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
1108
1109         pos_y += ts_y;
1110         mySize_y -= ts_y;
1111
1112         vector player_fontsize = hud_fontsize * 1.75;
1113         ts_y = ( mySize_y - 2*player_fontsize_y ) / BD_TEAMS;
1114         ts_x = mySize_x;
1115         vector mypos;
1116         vector tile_size = '48 48 0';
1117
1118         mypos = pos;
1119         drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
1120         mypos_y += player_fontsize_y;
1121         drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
1122
1123         entity e;
1124         FOREACH_MINIGAME_ENTITY(e)
1125         {
1126                 if ( e.classname == "minigame_player" )
1127                 {
1128                         mypos = pos;
1129                         minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
1130                                 entcs_GetName(e.minigame_playerslot-1),
1131                                 player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
1132
1133                         mypos_y += player_fontsize_y;
1134                         string thepiece = "bd/dozer";
1135                         if(active_minigame.minigame_flags & BD_TURN_EDIT)
1136                                 thepiece = bd_get_tile_pic(bd_curr_tile);
1137                         drawpic( mypos,
1138                                         minigame_texture(thepiece),
1139                                         tile_size * 0.7, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
1140
1141                         mypos_x += tile_size_x;
1142
1143                         drawstring(mypos,ftos(e.bd_moves),tile_size,
1144                                            '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
1145                 }
1146         }
1147 }
1148
1149 // Turn a set of flags into a help message
1150 string bd_turn_to_string(int turnflags)
1151 {
1152         if ( turnflags & BD_TURN_LOSS )
1153                 return _("Better luck next time!");
1154
1155         if ( turnflags & BD_TURN_WIN )
1156                 if(random() > 0.5)
1157                         return _("Tubular! Press \"Next Level\" to continue!");
1158                 else
1159                         return _("Wicked! Press \"Next Level\" to continue!");
1160
1161         if( turnflags & BD_TURN_EDIT )
1162                 return _("Press the space bar to change your currently selected tile");
1163
1164         if ( turnflags & BD_TURN_MOVE )
1165                 return _("Push the boulders onto the targets");
1166
1167         return "";
1168 }
1169
1170 // Make the correct move
1171 void bd_make_move(entity minigame, string dir)
1172 {
1173         if ( minigame.minigame_flags == BD_TURN_MOVE )
1174         {
1175                 minigame_cmd("move ", dir);
1176         }
1177 }
1178
1179 void bd_editor_make_move(entity minigame, string dir)
1180 {
1181         if ( minigame.minigame_flags == BD_TURN_EDIT )
1182         {
1183                 minigame_cmd("move ", bd_curr_pos, " ", ftos(bd_curr_tile), " ", dir);
1184         }
1185 }
1186
1187 void bd_editor_fill(entity minigame)
1188 {
1189         if ( minigame.minigame_flags == BD_TURN_EDIT )
1190         {
1191                 minigame_cmd("fill ", bd_curr_pos, " ", ftos(bd_curr_tile));
1192         }
1193 }
1194
1195 void bd_set_curr_pos(string s)
1196 {
1197         if ( bd_curr_pos )
1198                 strunzone(bd_curr_pos);
1199         if ( s )
1200                 s = strzone(s);
1201         bd_curr_pos = s;
1202 }
1203
1204 bool bd_normal_move(entity minigame, int themove)
1205 {
1206         switch ( themove )
1207         {
1208                 case K_RIGHTARROW:
1209                 case K_KP_RIGHTARROW:
1210                         bd_make_move(minigame, "r");
1211                         return true;
1212                 case K_LEFTARROW:
1213                 case K_KP_LEFTARROW:
1214                         bd_make_move(minigame, "l");
1215                         return true;
1216                 case K_UPARROW:
1217                 case K_KP_UPARROW:
1218                         bd_make_move(minigame, "u");
1219                         return true;
1220                 case K_DOWNARROW:
1221                 case K_KP_DOWNARROW:
1222                         bd_make_move(minigame, "d");
1223                         return true;
1224         }
1225
1226         return false;
1227 }
1228
1229 bool bd_change_dozer_angle(entity minigame)
1230 {
1231         entity dozer = bd_find_piece(minigame, bd_curr_pos, false);
1232         if(!dozer || dozer.bd_tiletype != BD_TILE_DOZER)
1233                 return false;
1234
1235         switch(dozer.bd_dir)
1236         {
1237                 case BD_DIR_UP: dozer.bd_dir = BD_DIR_LF; break; // up -> left
1238                 default:
1239                 case BD_DIR_DN: dozer.bd_dir = BD_DIR_RT; break; // down -> right
1240                 case BD_DIR_LF: dozer.bd_dir = BD_DIR_DN; break; // left -> down
1241                 case BD_DIR_RT: dozer.bd_dir = BD_DIR_UP; break; // right -> up
1242         }
1243         string thedir = bd_get_dir_name(dozer.bd_dir);
1244
1245         bd_editor_make_move(minigame, thedir);
1246         return true;
1247 }
1248
1249 bool bd_editor_move(entity minigame, int themove)
1250 {
1251         switch ( themove )
1252         {
1253                 case K_RIGHTARROW:
1254                 case K_KP_RIGHTARROW:
1255                         if ( ! bd_curr_pos )
1256                                 bd_set_curr_pos("a3");
1257                         else
1258                                 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,1,0,BD_NUM_CNT,BD_LET_CNT));
1259                         return true;
1260                 case K_LEFTARROW:
1261                 case K_KP_LEFTARROW:
1262                         if ( ! bd_curr_pos )
1263                                 bd_set_curr_pos("c3");
1264                         else
1265                                 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,-1,0,BD_NUM_CNT,BD_LET_CNT));
1266                         return true;
1267                 case K_UPARROW:
1268                 case K_KP_UPARROW:
1269                         if ( ! bd_curr_pos )
1270                                 bd_set_curr_pos("a1");
1271                         else
1272                                 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,0,1,BD_NUM_CNT,BD_LET_CNT));
1273                         return true;
1274                 case K_DOWNARROW:
1275                 case K_KP_DOWNARROW:
1276                         if ( ! bd_curr_pos )
1277                                 bd_set_curr_pos("a3");
1278                         else
1279                                 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,0,-1,BD_NUM_CNT,BD_LET_CNT));
1280                         return true;
1281                 case K_ENTER:
1282                 case K_KP_ENTER:
1283                         bd_editor_make_move(minigame, "");
1284                         return true;
1285                 case K_SPACE:
1286                         if(bd_change_dozer_angle(minigame))
1287                                 return true;
1288                         bd_curr_tile += 1;
1289                         if(bd_curr_tile > BD_TILE_LAST)
1290                                 bd_curr_tile = 1;
1291                         return true;
1292         }
1293
1294         return false;
1295 }
1296
1297 // Required function, handle client events
1298 int bd_client_event(entity minigame, string event, ...)
1299 {
1300         switch(event)
1301         {
1302                 case "activate":
1303                 {
1304                         minigame.message = bd_turn_to_string(minigame.minigame_flags);
1305                         bd_set_curr_pos("");
1306                         bd_curr_tile = BD_TILE_BRICK1;
1307                         return false;
1308                 }
1309                 case "key_pressed":
1310                 {
1311                         if(minigame.minigame_flags & BD_TURN_MOVE)
1312                         {
1313                                 if(bd_normal_move(minigame, ...(0,int)))
1314                                         return true;
1315                         }
1316
1317                         if(minigame.minigame_flags & BD_TURN_EDIT)
1318                         {
1319                                 if(bd_editor_move(minigame, ...(0,int)))
1320                                         return true;
1321                         }
1322
1323                         return false;
1324                 }
1325                 case "mouse_pressed":
1326                 {
1327                         if(minigame.minigame_flags & BD_TURN_EDIT)
1328                         {
1329                                 if(...(0,int) == K_MOUSE1)
1330                                 {
1331                                         bd_editor_make_move(minigame, "");
1332                                         return true;
1333                                 }
1334
1335                                 if(...(0,int) == K_MOUSE2)
1336                                 {
1337                                         bd_editor_fill(minigame);
1338                                         return true;
1339                                 }
1340                         }
1341
1342                         return false;
1343                 }
1344                 case "mouse_moved":
1345                 {
1346                         if(minigame.minigame_flags & BD_TURN_EDIT)
1347                         {
1348                                 vector mouse_pos = minigame_hud_normalize(mousepos,bd_boardpos,bd_boardsize);
1349                                 bd_set_curr_pos(minigame_tile_name(mouse_pos,BD_LET_CNT,BD_NUM_CNT));
1350                                 if ( ! bd_valid_tile(bd_curr_pos) )
1351                                         bd_set_curr_pos("");
1352                         }
1353                         return true;
1354                 }
1355                 case "network_receive":
1356                 {
1357                         entity sent = ...(0,entity);
1358                         int sf = ...(1,int);
1359                         if ( sent.classname == "minigame" )
1360                         {
1361                                 if ( sf & MINIG_SF_UPDATE )
1362                                 {
1363                                         sent.message = bd_turn_to_string(sent.minigame_flags);
1364                                         //if ( sent.minigame_flags & minigame_self.team )
1365                                                 minigame_prompt();
1366                                 }
1367                         }
1368                         else if(sent.classname == "minigame_board_piece")
1369                         {
1370                                 if(sf & MINIG_SF_UPDATE)
1371                                 {
1372                                         int letter = ReadByte();
1373                                         int number = ReadByte();
1374                                         if(sent.netname) { strunzone(sent.netname); }
1375                                         sent.netname = strzone(minigame_tile_buildname(letter, number));
1376
1377                                         sent.bd_tiletype = ReadByte();
1378
1379                                         sent.bd_dir = ReadByte();
1380                                 }
1381                         }
1382                         else if(sent.classname == "minigame_player" && (sf & BD_SF_PLAYERMOVES))
1383                                 sent.bd_moves = ReadShort(); // make this a byte when possible
1384
1385                         return false;
1386                 }
1387                 case "menu_show":
1388                 {
1389                         HUD_MinigameMenu_CustomEntry(...(0,entity),_("Next Level"),"next");
1390                         HUD_MinigameMenu_CustomEntry(...(0,entity),_("Restart"),"restart");
1391                         HUD_MinigameMenu_CustomEntry(...(0,entity),_("Editor"),"edit");
1392                         HUD_MinigameMenu_CustomEntry(...(0,entity),_("Save"),"save");
1393                         return false;
1394                 }
1395                 case "menu_click":
1396                 {
1397                         if(...(0,string) == "next")
1398                                 minigame_cmd("next");
1399                         if(...(0,string) == "restart")
1400                                 minigame_cmd("restart");
1401                         if(...(0,string) == "edit")
1402                                 minigame_cmd("edit");
1403                         if(...(0,string) == "save")
1404                                 minigame_cmd("save");
1405                         return false;
1406                 }
1407         }
1408
1409         return false;
1410 }
1411
1412 #endif