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