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