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 = findfloat(e,minigame_id,minig.minigame_id) ) )
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 = findfloat(e,minigame_id,minig.minigame_id) ) )
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 = findfloat(e,minigame_id,minig.minigame_id) ) )
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);
123 WriteRegistered(Minigames, MSG_ENTITY, this.descriptor);
124
125 if(sf & BD_SF_UPDATE_SINGLE)
126 {
127 int number = this.bd_forceupdate;
128 //this.bd_forceupdate = 0;
129 int ttype = this.bd_tiletypes[number];
130 int dir = this.bd_dirs[number];
132 WriteByte(MSG_ENTITY, ttype);
134 }
135
136 if(sf & BD_SF_UPDATE_ALL)
137 {
138 for(int j = 0; j < BD_NUM_CNT; ++j)
139 {
140 int ttype = this.bd_tiletypes[j];
141 int dir = this.bd_dirs[j];
142 WriteByte(MSG_ENTITY, ttype);
144 }
145 }
146
147 return true;
148}
149#elif defined(CSQC)
150NET_HANDLE(ENT_CLIENT_BD_CONTROLLER, bool isNew)
151{
152 this.classname = "bd_controller";
153 return = true;
154
155 int sf = ReadByte();
156 this.bd_tilelet = ReadByte();
157 this.minigame_id = ReadShort();
158 this.descriptor = ReadRegistered(Minigames);
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 = findfloat(e,minigame_id,minig.minigame_id) ) )
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 = findfloat(e,minigame_id,minigame.minigame_id) ) )
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 = findfloat(e,minigame_id,minigame.minigame_id)) )
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 = findfloat(e, minigame_id, minigame.minigame_id)) )
568 if(e.classname == "minigame_board_piece")
569 {
570 strfree(e.netname);
571 delete(e);
572 }
573 e = NULL;
574 while( (e = findfloat(e, minigame_id, minigame.minigame_id)) )
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.minigame_id = minigame.minigame_id;
585 controller.descriptor = minigame.descriptor;
586 controller.bd_tilelet = letter;
587 #ifdef SVQC
588 Net_LinkEntity(controller, false, 0, bd_controller_send);
589 #endif
590 }
591
592 bd_load_level(minigame);
593}
594
595void bd_do_next_match(entity minigame, entity player)
596{
597 minigame.minigame_flags = BD_TURN_MOVE;
599
600 if(minigame.bd_nextlevel && minigame.bd_nextlevel != "")
601 {
602 strcpy(minigame.bd_levelname, minigame.bd_nextlevel);
603 }
604
605 bd_setup_pieces(minigame);
606
607 bd_reset_moves(minigame);
608}
609
610void bd_set_next_match(entity minigame, string next)
611{
612 strcpy(minigame.bd_nextlevel, next);
613}
614
615void bd_next_match(entity minigame, entity player, string next)
616{
617 if(minigame.minigame_flags & BD_TURN_WIN)
618 bd_do_next_match(minigame, player);
619 if(minigame.minigame_flags & BD_TURN_EDIT)
620 bd_set_next_match(minigame, next);
621}
622
623// request a new match
624void bd_restart_match(entity minigame, entity player)
625{
626 minigame.minigame_flags = BD_TURN_MOVE;
628
629 bd_setup_pieces(minigame);
630
631 bd_reset_moves(minigame);
632}
633
634void bd_activate_editor(entity minigame, entity player)
635{
636#ifdef SVQC
637 if(!player.minigame_players.bd_canedit)
638 {
639 sprint(player.minigame_players, "You're not allowed to edit levels, sorry!\n");
640 return;
641 }
642#endif
643
644 minigame.minigame_flags = BD_TURN_EDIT;
646
647 bd_reset_moves(minigame);
648
649 bd_setup_pieces(minigame);
650}
651
653{
654 string bd_string = "";
655
656 string tilename = minigame_tile_buildname(e.bd_tilelet, number);
657
658 bd_string = strcat(bd_string, "\"", tilename, "\" ");
659 bd_string = strcat(bd_string, ftos(e.bd_tiletypes[number]), " ");
660 bd_string = strcat(bd_string, ftos(e.bd_dirs[number]));
661
662 return bd_string;
663}
664
665string bd_save_piece(entity minigame, entity e)
666{
667 string bd_string = "";
668
669 bd_string = strcat(bd_string, "\"", e.netname, "\" ");
670 bd_string = strcat(bd_string, ftos(e.bd_tiletype), " ");
671 bd_string = strcat(bd_string, ftos(e.bd_dir));
672
673 return bd_string;
674}
675
676void bd_set_nextlevel(entity minigame, string s)
677{
679
680 strcpy(minigame.bd_nextlevel, argv(2));
681}
682
684{
685 if(dir.x == 0 && dir.y == 1) { return BD_DIR_UP; } // up
686 if(dir.x == 0 && dir.y == -1) { return BD_DIR_DN; } // down
687 if(dir.x == -1 && dir.y == 0) { return BD_DIR_LF; } // left
688 if(dir.x == 1 && dir.y == 0) { return BD_DIR_RT; } // right
689
690 return BD_DIR_DN; // down if all else fails
691}
692
693void bd_load_piece(entity minigame, string s)
694{
695 // separate pieces between the ; symbols
696 string bd_string = s;
697
698 tokenize_console(bd_string);
699
700 int argv_num = 0;
701 string tilename = strzone(argv(argv_num)); ++argv_num;
702 int tiletype = stoi(argv(argv_num)); ++argv_num;
703 int dir = stoi(argv(argv_num)); ++argv_num;
704
705 if(bd_canfill(tiletype))
706 {
707 int letter = minigame_tile_letter(tilename);
708 int number = minigame_tile_number(tilename);
709 entity controller = bd_find_controller(minigame, letter);
710 controller.bd_tiletypes[number] = tiletype;
711 controller.bd_dirs[number] = dir;
712
713 bd_controller_update(controller, number);
714 }
715 else
716 {
717 entity e = msle_spawn(minigame,new(minigame_board_piece));
718 e.netname = tilename;
719 e.team = 1;
720 e.bd_dir = dir;
721 e.bd_tiletype = tiletype;
723 }
724}
725
726bool bd_save_level(entity minigame)
727{
728 if(minigame.bd_levelname && minigame.bd_levelname != "")
729 {
730 int target_count = 0, boulder_count = 0;
731 entity piece = NULL;
732 while((piece = findfloat(piece,minigame_id,minigame.minigame_id)))
733 if(piece.classname == "minigame_board_piece")
734 {
735 if(piece.bd_tiletype == BD_TILE_BOULDER)
736 ++boulder_count;
737 else if(piece.bd_tiletype == BD_TILE_TARGET)
738 ++target_count;
739 }
740
741 if(boulder_count != target_count)
742 {
743 LOG_INFO("Not enough targets or boulders, fix your level!");
744 return false;
745 }
746
747 // saves all objects to the database file
748 string file_name;
749 float file_get;
750
751 file_name = strcat("minigames/bulldozer/storage_", minigame.bd_levelname, ".txt");
752 file_get = fopen(file_name, FILE_WRITE);
753 fputs(file_get, strcat("// bulldozer storage \"", minigame.bd_levelname, "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S"), "\n"));
754
755 if(minigame.bd_nextlevel && minigame.bd_nextlevel != "" && fexists(strcat("minigames/bulldozer/storage_", minigame.bd_nextlevel, ".txt")))
756 fputs(file_get, strcat("nextlevel = \"", minigame.bd_nextlevel, "\"\n"));
757
758 entity e = NULL;
759 while ( ( e = findfloat(e,minigame_id,minigame.minigame_id) ) )
760 if ( e.classname == "bd_controller" )
761 {
762 for(int j = 0; j < BD_NUM_CNT; ++j)
763 {
764 // use a line of text for each object, listing all properties
765 fputs(file_get, strcat(bd_save_controller_piece(minigame, e, j), "\n"));
766 }
767 }
768 e = NULL;
769
770 while ( ( e = findfloat(e,minigame_id,minigame.minigame_id) ) )
771 if ( e.classname == "minigame_board_piece" )
772 {
773 // use a line of text for each object, listing all properties
774 fputs(file_get, strcat(bd_save_piece(minigame, e), "\n"));
775 }
776 fclose(file_get);
777
778 return true;
779 }
780
781 return false;
782}
783
784void bd_load_level(entity minigame)
785{
786 // loads all items from the database file
787 string file_read, file_name;
788 float file_get;
789
790 file_name = strcat("minigames/bulldozer/storage_", minigame.bd_levelname, ".txt");
791 file_get = fopen(file_name, FILE_READ);
792 if(file_get < 0)
793 {
794 LOG_INFO("^3BULLDOZER: ^7could not find storage file ^3", file_name, "^7, no items were loaded");
795 }
796 else
797 {
798 for(;;)
799 {
800 file_read = fgets(file_get);
801 if(file_read == "")
802 break;
803 if(substring(file_read, 0, 2) == "//")
804 continue;
805 if(substring(file_read, 0, 1) == "#")
806 continue;
807 if(substring(file_read, 0, 9) == "nextlevel")
808 {
809 bd_set_nextlevel(minigame, file_read);
810 continue;
811 }
812
813 bd_load_piece(minigame, file_read);
814 }
815 }
816 fclose(file_get);
817}
818
819void bd_close_editor(entity minigame, entity player)
820{
821#ifdef SVQC
822 if(!player.minigame_players.bd_canedit)
823 {
824 sprint(player.minigame_players, "You're not allowed to edit levels, sorry!\n");
825 return;
826 }
827#endif
828
829 entity dozer = bd_find_dozer(minigame);
830 if(!dozer)
831 {
832 LOG_INFO("You need to place a bulldozer on the level to save it!");
833 return;
834 }
835
836 if(bd_save_level(minigame))
837 {
838 minigame.minigame_flags = BD_TURN_MOVE;
840 }
841 else
842 {
843 LOG_INFO("You need to set the level name!");
844 return;
845 }
846}
847
848#ifdef SVQC
849
850// required function, handle server side events
851int bd_server_event(entity minigame, string event, ...)
852{
853 switch(event)
854 {
855 case "start":
856 {
858 bd_setup_pieces(minigame);
859 minigame.minigame_flags = BD_TURN_MOVE;
860
861 return true;
862 }
863 case "end":
864 {
865 entity e = NULL;
866 while( (e = findfloat(e, minigame_id, minigame.minigame_id)) )
867 if(e.classname == "minigame_board_piece")
868 {
869 strfree(e.netname);
870 delete(e);
871 }
872 e = NULL;
873 while( (e = findfloat(e, minigame_id, minigame.minigame_id)) )
874 if(e.classname == "bd_controller")
875 {
876 delete(e);
877 }
878
879 strfree(minigame.bd_nextlevel);
880 strfree(minigame.bd_levelname);
881 return false;
882 }
883 case "join":
884 {
885 int pl_num = minigame_count_players(minigame);
886
887 if(pl_num >= BD_TEAMS) { return BD_SPECTATOR_TEAM; }
888
889 return 1;
890 }
891 case "cmd":
892 {
893 entity player = ...(0,entity);
894 bool event_blocked = (player.team == BD_SPECTATOR_TEAM);
895 switch(argv(0))
896 {
897 case "move":
898 if(event_blocked)
899 return true;
900 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));
901 return true;
902 case "next":
903 if(event_blocked)
904 return true;
905 bd_next_match(minigame,...(0,entity), ((...(1,int) >= 2 ? argv(1) : string_null)));
906 return true;
907 case "restart":
908 if(event_blocked)
909 return true;
910 bd_restart_match(minigame,...(0,entity));
911 return true;
912 case "edit":
913 if(event_blocked)
914 return true;
915 bd_activate_editor(minigame,...(0,entity));
916 return true;
917 case "save":
918 if(event_blocked)
919 return true;
920 bd_close_editor(minigame,...(0,entity));
921 return true;
922 case "fill":
923 if(event_blocked)
924 return true;
925 bd_do_fill(minigame, ...(0,entity), ((...(1,int)) >= 2 ? argv(1) : string_null), ((...(1,int)) >= 3 ? argv(2) : string_null));
926 return true;
927 }
928
929 return false;
930 }
931 case "network_send":
932 {
933 entity sent = ...(0,entity);
934 int sf = ...(1,int);
935 if ( sent.classname == "minigame_board_piece" && (sf & MINIG_SF_UPDATE) )
936 {
937 int letter = minigame_tile_letter(sent.netname);
938 int number = minigame_tile_number(sent.netname);
939
940 WriteByte(MSG_ENTITY,letter);
942
943 WriteByte(MSG_ENTITY,sent.bd_tiletype);
944
945 WriteByte(MSG_ENTITY,sent.bd_dir);
946 }
947 else if(sent.classname == "minigame_player" && (sf & BD_SF_PLAYERMOVES))
948 WriteShort(MSG_ENTITY,sent.bd_moves);
949 return false;
950 }
951 }
952
953 return false;
954}
955
956
957#elif defined(CSQC)
958
959int bd_curr_tile;
960string bd_curr_pos;
961
962.entity bd_enemy;
963.bool bd_hide;
964
965vector bd_boardpos; // HUD board position
966vector bd_boardsize;// HUD board size
967
968string bd_get_tile_pic(int tileid)
969{
970 switch(tileid)
971 {
972 case BD_TILE_BOULDER: return "bd/boulder";
973 case BD_TILE_BRICK1: return "bd/brick1";
974 case BD_TILE_BRICK2: return "bd/brick2";
975 case BD_TILE_BRICK3: return "bd/brick3";
976 case BD_TILE_BRICK4: return "bd/brick4";
977 case BD_TILE_BRICK5: return "bd/brick5";
978 case BD_TILE_BRICK6: return "bd/brick6";
979 case BD_TILE_BRICK7: return "bd/brick7";
980 case BD_TILE_BRICK8: return "bd/brick8";
981 case BD_TILE_TARGET: return "bd/target";
982 case BD_TILE_DOZER: return "bd/dozer";
983 }
984
985 return string_null;
986}
987
988// Required function, draw the game board
989void bd_hud_board(vector pos, vector mySize)
990{
991 minigame_hud_fitsqare(pos, mySize);
992 bd_boardpos = pos;
993 bd_boardsize = mySize;
994
995 minigame_hud_simpleboard(pos,mySize,minigame_texture("bd/board"));
996
997 vector tile_size = minigame_hud_denormalize_size('1 1 0' / BD_TILE_SIZE,pos,mySize);
998 vector tile_pos;
999
1000 entity e;
1002 {
1003 if(e.classname == "minigame_board_piece")
1004 {
1005 if(e.bd_tiletype == BD_TILE_TARGET)
1006 {
1007 e.bd_enemy = NULL;
1008 e.bd_enemy = bd_find_piece(active_minigame, e.netname, false);
1009 }
1010 else if(e.bd_tiletype == BD_TILE_BOULDER)
1011 {
1012 e.bd_hide = false; // reset either way
1013 e.bd_hide = ((bd_find_piece(active_minigame, e.netname, true)) != NULL);
1014 }
1015 }
1016 }
1018 {
1019 if ( e.classname == "bd_controller" )
1020 {
1021 for(int j = 0; j < BD_NUM_CNT; ++j)
1022 {
1023 if(!e.bd_tiletypes[j]) continue;
1024
1025 int letter = e.bd_tilelet;
1026 string mypos = minigame_tile_buildname(letter, j);
1027
1028 tile_pos = minigame_tile_pos(mypos,BD_NUM_CNT,BD_LET_CNT);
1029 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1030
1031 string thepiece = bd_get_tile_pic(e.bd_tiletypes[j]);
1032
1033 minigame_drawpic_centered( tile_pos,
1034 minigame_texture(thepiece),
1035 tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
1036 }
1037 }
1038 else if ( e.classname == "minigame_board_piece" )
1039 {
1040 if(e.bd_tiletype != BD_TILE_DOZER && !e.bd_hide) // hide boulders
1041 {
1042 tile_pos = minigame_tile_pos(e.netname,BD_NUM_CNT,BD_LET_CNT);
1043 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1044
1045 string thepiece = bd_get_tile_pic(e.bd_tiletype);
1046
1047 if(e.bd_enemy)
1048 thepiece = "bd/boulder_target";
1049
1050 minigame_drawpic_centered( tile_pos,
1051 minigame_texture(thepiece),
1052 tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
1053 }
1054 }
1055 }
1056
1057 // draw dozers on top, always
1059 {
1060 if ( e.classname == "minigame_board_piece" && e.bd_tiletype == BD_TILE_DOZER )
1061 {
1062 tile_pos = minigame_tile_pos(e.netname,BD_NUM_CNT,BD_LET_CNT);
1063 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1064
1065 int bdir = e.bd_dir;
1066 float theang = 0;
1067
1068 switch(bdir)
1069 {
1070 case BD_DIR_UP: theang = 0; break;
1071 default:
1072 case BD_DIR_DN: theang = M_PI; break;
1073 case BD_DIR_LF: theang = M_PI * 3 / 2; break;
1074 case BD_DIR_RT: theang = M_PI / 2; break;
1075 }
1076
1077 drawrotpic(tile_pos, theang, minigame_texture("bd/dozer"),
1078 tile_size, tile_size/2, '1 1 1',
1080 }
1081 }
1082
1083 if(active_minigame.minigame_flags & BD_TURN_EDIT)
1084 if(bd_valid_tile(bd_curr_pos))
1085 {
1086 entity piece = bd_find_piece(active_minigame, bd_curr_pos, false);
1087 entity targ = bd_find_piece(active_minigame, bd_curr_pos, true);
1088 string thepiece = ((piece || (targ && bd_curr_tile != BD_TILE_BOULDER)) ? "bd/delete" : bd_get_tile_pic(bd_curr_tile));
1089
1090 tile_pos = minigame_tile_pos(bd_curr_pos,BD_LET_CNT,BD_NUM_CNT);
1091 tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
1092 if(bd_curr_tile == BD_TILE_DOZER)
1093 {
1094 drawrotpic(tile_pos, M_PI, minigame_texture("bd/dozer"),
1095 tile_size, tile_size/2, '1 1 1',
1097 }
1098 else
1099 {
1100 minigame_drawpic_centered( tile_pos,
1101 minigame_texture(thepiece),
1102 tile_size, '1 1 1', panel_fg_alpha/2, DRAWFLAG_NORMAL );
1103 }
1104 }
1105
1106 if(active_minigame.minigame_flags & (BD_TURN_LOSS | BD_TURN_WIN))
1107 {
1108 vector winfs = hud_fontsize*2;
1109 string victory_text = _("Game over!");
1110
1111 if(active_minigame.minigame_flags & BD_TURN_WIN)
1112 victory_text = _("Well done! Click \"Next Level\" to continue");
1113
1114 vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
1115 vector win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
1116 victory_text, winfs, 0, DRAWFLAG_NORMAL, 0.5);
1117
1118 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);
1119
1121 victory_text, winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
1122 }
1123
1124 minigame_show_allspecs(bd_boardpos, bd_boardsize);
1125}
1126
1127
1128// Required function, draw the game status panel
1129void bd_hud_status(vector pos, vector mySize)
1130{
1132 vector 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;
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:624
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:683
const int BD_DIR_DN
Definition bd.qc:59
void bd_next_match(entity minigame, entity player, string next)
Definition bd.qc:615
int bd_server_event(entity minigame, string event,...)
Definition bd.qc:851
void bd_do_next_match(entity minigame, entity player)
Definition bd.qc:595
void bd_setup_pieces(entity minigame)
Definition bd.qc:564
void bd_close_editor(entity minigame, entity player)
Definition bd.qc:819
void bd_set_next_match(entity minigame, string next)
Definition bd.qc:610
void bd_activate_editor(entity minigame, entity player)
Definition bd.qc:634
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:726
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:693
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:652
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:676
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:784
int bd_forceupdate
Definition bd.qc:39
string bd_save_piece(entity minigame, entity e)
Definition bd.qc:665
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_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
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
WriteByte(chan, ent.angles.y/DEC_FACTOR)
string entcs_GetName(int i)
Definition ent_cs.qh:148
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:75
#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 ReadRegistered(r)
Definition net.qh:290
#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 WriteRegistered(r, to, it)
Definition net.qh:292
#define LOG_INFO(...)
Definition log.qh:62
#define M_PI
pi
Definition mathlib.qh:114
string fgets(float fhandle)
void fclose(float fhandle)
float stof(string val,...)
void fputs(float fhandle, string s)
string substring(string s, float start, float length)
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)
string strzone(string s)
string argv(float n)
entity findfloat(entity start,.float field, float match)
entity msle_spawn(entity minigame_session, entity e)
Definition minigames.qc:96
string minigame_relative_tile(string start_id, int dx, int dy, int rows, int columns)
Definition minigames.qc:49
void minigame_server_sendflags(entity ent, int mgflags)
Definition minigames.qc:87
int minigame_count_players(entity minigame)
Definition minigames.qc:132
int minigame_tile_letter(string id)
Definition minigames.qc:21
string minigame_tile_name(vector pos, int rows, int columns)
Definition minigames.qc:63
vector minigame_tile_pos(string id, int rows, int columns)
Definition minigames.qc:36
string minigame_tile_buildname(int letter, int number)
Definition minigames.qc:43
int minigame_tile_number(string id)
Definition minigames.qc:30
int minigame_id
Unique ID for the minigame session, associated with all objects currently the result of etof(minigame...
Definition minigames.qh:49
const int MINIG_SF_UPDATE
Definition minigames.qh:113
const int MINIG_SF_ALL
Definition minigames.qh:116
const int MINIG_SF_CUSTOM
Definition minigames.qh:114
entity descriptor
For minigame sessions: minigame descriptor object.
Definition minigames.qh:45
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:66
#define NULL
Definition post.qh:14
vector
Definition self.qh:96
int dir
Definition impulse.qc:89
int int number
Definition impulse.qc:89
#define strfree(this)
Definition string.qh:57
#define strcpy(this, s)
Definition string.qh:51
const vector eY
Definition vector.qh:44
const vector eX
Definition vector.qh:43
void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)