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;
1114 win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
1115 victory_text, winfs, 0, DRAWFLAG_NORMAL, 0.5);
1116
1117 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);
1118
1120 victory_text, winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
1121 }
1122
1123 minigame_show_allspecs(bd_boardpos, bd_boardsize);
1124}
1125
1126
1127// Required function, draw the game status panel
1128void bd_hud_status(vector pos, vector mySize)
1129{
1131 vector ts;
1132 ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
1133 hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
1134
1135 pos_y += ts_y;
1136 mySize_y -= ts_y;
1137
1138 vector player_fontsize = hud_fontsize * 1.75;
1139 ts_y = ( mySize_y - 2*player_fontsize_y ) / BD_TEAMS;
1140 ts_x = mySize_x;
1141 vector mypos;
1142 vector tile_size = '48 48 0';
1143
1145 {
1146 mypos = pos;
1147 drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5*panel_fg_alpha,DRAWFLAG_ADDITIVE);
1148 mypos_y += player_fontsize_y;
1149 drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25*panel_fg_alpha,DRAWFLAG_ADDITIVE);
1150 }
1151
1152 entity e;
1154 {
1155 if ( e.classname == "minigame_player" && e.team != BD_SPECTATOR_TEAM )
1156 {
1157 mypos = pos;
1159 entcs_GetName(e.minigame_playerslot-1),
1160 player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
1161
1162 mypos_y += player_fontsize_y;
1163 string thepiece = "bd/dozer";
1164 if(active_minigame.minigame_flags & BD_TURN_EDIT)
1165 thepiece = bd_get_tile_pic(bd_curr_tile);
1166 const float tile_scale = 0.7;
1167 drawpic( mypos + tile_size * 0.5 * (1 - tile_scale),
1168 minigame_texture(thepiece),
1169 tile_size * tile_scale, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
1170
1171 mypos_x += tile_size_x;
1172
1173 drawstring(mypos,ftos(e.bd_moves),tile_size,
1174 '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
1175 }
1176 }
1177}
1178
1179// Turn a set of flags into a help message
1180string bd_turn_to_string(int turnflags)
1181{
1183 return _("You are spectating");
1184
1185 if ( turnflags & BD_TURN_LOSS )
1186 return _("Better luck next time!");
1187
1188 if ( turnflags & BD_TURN_WIN )
1189 {
1190 if(random() > 0.5)
1191 return _("Tubular! Press \"Next Level\" to continue!");
1192 else
1193 return _("Wicked! Press \"Next Level\" to continue!");
1194 }
1195
1196 if( turnflags & BD_TURN_EDIT )
1197 return _("Press the spacebar to change your currently selected tile");
1198
1199 if ( turnflags & BD_TURN_MOVE )
1200 return _("Push the boulders onto the targets");
1201
1202 return "";
1203}
1204
1205// Make the correct move
1206void bd_make_move(entity minigame, string dir)
1207{
1208 if ( minigame.minigame_flags == BD_TURN_MOVE )
1209 {
1210 minigame_cmd("move ", dir);
1211 }
1212}
1213
1214void bd_editor_make_move(entity minigame, string dir)
1215{
1216 if ( minigame.minigame_flags == BD_TURN_EDIT )
1217 {
1218 minigame_cmd("move ", bd_curr_pos, " ", ftos(bd_curr_tile), " ", dir);
1219 }
1220}
1221
1222void bd_editor_fill(entity minigame)
1223{
1224 if ( minigame.minigame_flags == BD_TURN_EDIT )
1225 {
1226 minigame_cmd("fill ", bd_curr_pos, " ", ftos(bd_curr_tile));
1227 }
1228}
1229
1230void bd_set_curr_pos(string s)
1231{
1232 strfree(bd_curr_pos);
1233 if ( s )
1234 s = strzone(s);
1235 bd_curr_pos = s;
1236}
1237
1238bool bd_change_dozer_angle(entity minigame)
1239{
1240 entity dozer = bd_find_piece(minigame, bd_curr_pos, false);
1241 if(!dozer || dozer.bd_tiletype != BD_TILE_DOZER)
1242 return false;
1243
1244 switch(dozer.bd_dir)
1245 {
1246 case BD_DIR_UP: dozer.bd_dir = BD_DIR_LF; break; // up -> left
1247 default:
1248 case BD_DIR_DN: dozer.bd_dir = BD_DIR_RT; break; // down -> right
1249 case BD_DIR_LF: dozer.bd_dir = BD_DIR_DN; break; // left -> down
1250 case BD_DIR_RT: dozer.bd_dir = BD_DIR_UP; break; // right -> up
1251 }
1252 string thedir = bd_get_dir_name(dozer.bd_dir);
1253
1254 bd_editor_make_move(minigame, thedir);
1255 return true;
1256}
1257
1258// Required function, handle client events
1259int bd_client_event(entity minigame, string event, ...)
1260{
1261 switch(event)
1262 {
1263 case "activate":
1264 {
1265 strcpy(minigame.message, bd_turn_to_string(minigame.minigame_flags));
1266 bd_set_curr_pos("");
1267 bd_curr_tile = BD_TILE_BRICK1;
1268 return false;
1269 }
1270 case "deactivate":
1271 {
1272 strfree(minigame.message);
1273 return false;
1274 }
1275 case "key_pressed":
1276 case "key_released":
1277 {
1278 bool event_blocked = ((event == "key_released")
1279 || !(minigame.minigame_flags & BD_TURN_MOVE) || (minigame_self.team == BD_SPECTATOR_TEAM));
1280 if (!(minigame.minigame_flags & (BD_TURN_WIN | BD_TURN_LOSS)))
1281 {
1282 switch ( ...(0,int) )
1283 {
1284 case K_RIGHTARROW:
1285 case K_KP_RIGHTARROW:
1286 if (event_blocked)
1287 return true;
1288 bd_make_move(minigame, "r");
1289 return true;
1290 case K_LEFTARROW:
1291 case K_KP_LEFTARROW:
1292 if (event_blocked)
1293 return true;
1294 bd_make_move(minigame, "l");
1295 return true;
1296 case K_UPARROW:
1297 case K_KP_UPARROW:
1298 if (event_blocked)
1299 return true;
1300 bd_make_move(minigame, "u");
1301 return true;
1302 case K_DOWNARROW:
1303 case K_KP_DOWNARROW:
1304 if (event_blocked)
1305 return true;
1306 bd_make_move(minigame, "d");
1307 return true;
1308 }
1309 }
1310
1311 if(minigame.minigame_flags & BD_TURN_EDIT)
1312 {
1313 switch ( ...(0,int) )
1314 {
1315 case K_RIGHTARROW:
1316 case K_KP_RIGHTARROW:
1317 if (event_blocked)
1318 return true;
1319 if ( ! bd_curr_pos )
1320 bd_set_curr_pos("a3");
1321 else
1322 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,1,0,BD_NUM_CNT,BD_LET_CNT));
1323 return true;
1324 case K_LEFTARROW:
1325 case K_KP_LEFTARROW:
1326 if (event_blocked)
1327 return true;
1328 if ( ! bd_curr_pos )
1329 bd_set_curr_pos("c3");
1330 else
1331 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,-1,0,BD_NUM_CNT,BD_LET_CNT));
1332 return true;
1333 case K_UPARROW:
1334 case K_KP_UPARROW:
1335 if (event_blocked)
1336 return true;
1337 if ( ! bd_curr_pos )
1338 bd_set_curr_pos("a1");
1339 else
1340 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,0,1,BD_NUM_CNT,BD_LET_CNT));
1341 return true;
1342 case K_DOWNARROW:
1343 case K_KP_DOWNARROW:
1344 if (event_blocked)
1345 return true;
1346 if ( ! bd_curr_pos )
1347 bd_set_curr_pos("a3");
1348 else
1349 bd_set_curr_pos(minigame_relative_tile(bd_curr_pos,0,-1,BD_NUM_CNT,BD_LET_CNT));
1350 return true;
1351 case K_ENTER:
1352 case K_KP_ENTER:
1353 if (event_blocked)
1354 return true;
1355 bd_editor_make_move(minigame, "");
1356 return true;
1357 case K_SPACE:
1358 if (event_blocked)
1359 return true;
1360 if(bd_change_dozer_angle(minigame))
1361 return true;
1362 bd_curr_tile += 1;
1363 if(bd_curr_tile > BD_TILE_LAST)
1364 bd_curr_tile = 1;
1365 return true;
1366 }
1367 }
1368
1369 return false;
1370 }
1371 case "mouse_pressed":
1372 {
1373 if((minigame.minigame_flags & BD_TURN_EDIT) && minigame_self.team != BD_SPECTATOR_TEAM)
1374 {
1375 if(...(0,int) == K_MOUSE1)
1376 {
1377 bd_client_event(minigame, "mouse_moved");
1378 bd_editor_make_move(minigame, "");
1379 return true;
1380 }
1381
1382 if(...(0,int) == K_MOUSE2)
1383 {
1384 bd_client_event(minigame, "mouse_moved");
1385 bd_editor_fill(minigame);
1386 return true;
1387 }
1388 }
1389
1390 return false;
1391 }
1392 case "mouse_moved":
1393 {
1394 if((minigame.minigame_flags & BD_TURN_EDIT) && minigame_self.team != BD_SPECTATOR_TEAM)
1395 {
1396 vector mouse_pos = minigame_hud_normalize(mousepos,bd_boardpos,bd_boardsize);
1397 bd_set_curr_pos(minigame_tile_name(mouse_pos,BD_LET_CNT,BD_NUM_CNT));
1398 if ( ! bd_valid_tile(bd_curr_pos) )
1399 bd_set_curr_pos("");
1400 }
1401 return true;
1402 }
1403 case "network_receive":
1404 {
1405 entity sent = ...(0,entity);
1406 int sf = ...(1,int);
1407 if ( sent.classname == "minigame" )
1408 {
1409 if ( sf & MINIG_SF_UPDATE )
1410 {
1411 strcpy(sent.message, bd_turn_to_string(sent.minigame_flags));
1412 //if ( sent.minigame_flags & minigame_self.team )
1413 //minigame_prompt();
1414 }
1415 }
1416 else if(sent.classname == "minigame_board_piece")
1417 {
1418 if(sf & MINIG_SF_UPDATE)
1419 {
1420 int letter = ReadByte();
1421 int number = ReadByte();
1422 strcpy(sent.netname, minigame_tile_buildname(letter, number));
1423
1424 sent.bd_tiletype = ReadByte();
1425
1426 sent.bd_dir = ReadByte();
1427 }
1428 }
1429 else if(sent.classname == "minigame_player" && (sf & BD_SF_PLAYERMOVES))
1430 sent.bd_moves = ReadShort(); // make this a byte when possible
1431
1432 return false;
1433 }
1434 case "menu_show":
1435 {
1436 HUD_MinigameMenu_CustomEntry(...(0,entity),_("Next Level"),"next");
1437 HUD_MinigameMenu_CustomEntry(...(0,entity),_("Restart"),"restart");
1438 HUD_MinigameMenu_CustomEntry(...(0,entity),_("Editor"),"edit");
1439 HUD_MinigameMenu_CustomEntry(...(0,entity),_("Save"),"save");
1440 return false;
1441 }
1442 case "menu_click":
1443 {
1444 if(...(0,string) == "next")
1445 minigame_cmd("next");
1446 if(...(0,string) == "restart")
1447 minigame_cmd("restart");
1448 if(...(0,string) == "edit")
1449 minigame_cmd("edit");
1450 if(...(0,string) == "save")
1451 minigame_cmd("save");
1452 return false;
1453 }
1454 }
1455
1456 return false;
1457}
1458
1459#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:93
#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:115
#define WriteHeader(to, id)
Definition net.qh:221
#define REGISTER_NET_LINKED(id)
Definition net.qh:55
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
Definition net.qh:123
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)