Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_nexball.qc
Go to the documentation of this file.
1#include "sv_nexball.qh"
2
3#include <server/client.qh>
5#include <server/gamelog.qh>
6#include <server/world.qh>
7#include <common/ent_cs.qh>
10
12
15
33
40
49
52void ResetBall(entity this);
53const int NBM_NONE = 0;
54const int NBM_FOOTBALL = 2;
55const int NBM_BASKETBALL = 4;
57
58float OtherTeam(float t) //works only if there are two teams on the map!
59{
60 entity e;
61 e = find(NULL, classname, "nexball_team");
62 if(e.team == t)
63 e = find(e, classname, "nexball_team");
64 return e.team;
65}
66
67const int ST_NEXBALL_GOALS = 1;
69{
71 field_team(ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
72 field(SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
73 field(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
74 });
75}
76
77void LogNB(string mode, entity actor)
78{
79 string s;
81 return;
82 s = strcat(":nexball:", mode);
83 if(actor != NULL)
84 s = strcat(s, ":", ftos(actor.playerid));
85 GameLogEcho(s);
86}
87
89{
90 if(this.owner)
91 DropBall(this, this.owner.origin, '0 0 0');
92 ResetBall(this);
93}
94
96{
97 STAT(OBJECTIVE_STATUS, this) &= ~NB_CARRYING;
98 if(this.ballcarried)
99 {
100 if(this.ballcarried.lifetime && (this.ballcarried.lifetime < time))
101 {
102 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
103 entity e = this.ballcarried;
104 DropBall(this.ballcarried, this.ballcarried.owner.origin, '0 0 0');
105 ResetBall(e);
106 }
107 else
108 STAT(OBJECTIVE_STATUS, this) |= NB_CARRYING;
109 }
110}
111
113{
114 tracebox(this.origin, BALL_MINS, BALL_MAXS, this.origin, true, this);
116 {
117 vector o = this.origin;
118 if (!move_out_of_solid(this)) {
119 objerror(this, "could not get out of solid at all!");
120 }
121 LOG_INFOF(
122 "^1NOTE: this map needs FIXING. %s at %s needs to be moved out of solid, e.g. by %s",
123 this.classname,
124 vtos(o - '0 0 1'),
125 vtos(this.origin - o)
126 );
127 this.origin = o;
128 }
129}
130
132{
133 entity ownr;
134 ownr = this.owner;
135 DropBall(this, ownr.origin, ownr.velocity);
136 makevectors(ownr.v_angle.y * '0 1 0');
137 ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
138 UNSET_ONGROUND(ownr);
139}
140
141void GiveBall(entity plyr, entity ball)
142{
143 .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
144 entity ownr = ball.owner;
145 if(ownr)
146 {
148 ownr.ballcarried = NULL;
149 GameRules_scoring_vip(ownr, false);
150 if(STAT(NB_METERSTART, ownr))
151 {
152 STAT(NB_METERSTART, ownr) = 0;
153 ownr.(weaponentity).state = WS_READY;
154 }
155 WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
156 }
157 else
158 {
159 WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
160 }
161
162 //setattachment(ball, plyr, "");
163 setorigin(ball, plyr.origin + plyr.view_ofs);
164
165 if(ball.team != plyr.team)
167
168 ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
169 ball.weaponentity_fld = weaponentity;
170 ball.team = plyr.team;
171 plyr.ballcarried = ball;
172 GameRules_scoring_vip(plyr, true);
173 ball.nb_dropper = plyr;
174
177
178 ball.velocity = '0 0 0';
180 settouch(ball, func_null);
181 ball.effects |= EF_NOSHADOW;
182 ball.scale = 1; // scale down.
183
184 WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
185 WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
186
188 {
189 setthink(ball, DropOwner);
191 }
192
193 STAT(WEAPONS, plyr.(weaponentity)) = STAT(WEAPONS, plyr);
194 plyr.m_switchweapon = plyr.(weaponentity).m_weapon;
195 STAT(WEAPONS, plyr) = WEPSET(NEXBALL);
196 Weapon w = WEP_NEXBALL;
197 w.wr_resetplayer(w, plyr);
198 plyr.(weaponentity).m_switchweapon = WEP_NEXBALL;
199 W_SwitchWeapon(plyr, WEP_NEXBALL, weaponentity);
200}
201
203{
205 ball.effects &= ~EF_NOSHADOW;
207
208 setattachment(ball, NULL, "");
209 setorigin(ball, org);
211 UNSET_ONGROUND(ball);
212 ball.scale = ball_scale;
213 ball.velocity = vel;
214 ball.nb_droptime = time;
216 setthink(ball, ResetBall);
217 ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.lifetime);
218
219 if(STAT(NB_METERSTART, ball.owner))
220 {
221 STAT(NB_METERSTART, ball.owner) = 0;
222 .entity weaponentity = ball.weaponentity_fld;
223 ball.owner.(weaponentity).state = WS_READY;
224 }
225
226 WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
227 WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
228 WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
229
230 entity e = ball.owner; ball.owner = NULL;
231 e.ballcarried = NULL;
232 GameRules_scoring_vip(e, false);
233}
234
235void InitBall(entity this)
236{
237 if(game_stopped) return;
238 UNSET_ONGROUND(this);
240 if(this.classname == "nexball_basketball")
242 else if(this.classname == "nexball_football")
244 this.cnt = 0;
245 setthink(this, ResetBall);
247 this.lifetime = 0;
248 this.pusher = NULL;
249 this.team = false;
252 LogNB("init", NULL);
253}
254
256{
257 if(this.cnt < 2) // step 1
258 {
259 if(time == this.lifetime)
260 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
261
262 settouch(this, func_null);
264 this.velocity = '0 0 0'; // just in case?
265 if(!this.cnt)
266 LogNB("resetidle", NULL);
267 this.cnt = 2;
268 this.nextthink = time;
269 }
270 else if(this.cnt < 4) // step 2 and 3
271 {
272// dprint("Step ", ftos(this.cnt), ": Calculated velocity: ", vtos(this.spawnorigin - this.origin), ", time: ", ftos(time), "\n");
273 this.velocity = (this.spawnorigin - this.origin) * (this.cnt - 1); // 1 or 0.5 second movement
274 this.nextthink = time + 0.5;
275 this.cnt += 1;
276 }
277 else // step 4
278 {
279// dprint("Step 4: time: ", ftos(time), "\n");
280 if(vdist(this.origin - this.spawnorigin, >, 10)) // should not happen anymore
281 LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
282 vtos(this.origin - this.spawnorigin), " Velocity: ", vtos(this.velocity), "\n");
283 this.velocity = '0 0 0';
284 setorigin(this, this.spawnorigin); // make sure it's positioned correctly anyway
286 setthink(this, InitBall);
288 }
289}
290
292{
293 if(toucher.solid == SOLID_BSP)
294 {
295 if(time > this.lastground + 0.1)
296 {
298 this.lastground = time;
299 }
300 if(this.velocity && !this.cnt)
302 return;
303 }
305 return;
306 if(GetResource(toucher, RES_HEALTH) < 1)
307 return;
308 if(!this.cnt)
310
311 this.pusher = toucher;
312 this.team = toucher.team;
313
314 if(autocvar_g_nexball_football_physics == -1) // MrBougo try 1, before decompiling Rev's original
315 {
316 if(toucher.velocity)
317 this.velocity = toucher.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
318 }
319 else if(autocvar_g_nexball_football_physics == 1) // MrBougo's modded Rev style: partially independant of the height of the aiming point
320 {
321 makevectors(toucher.v_angle);
323 }
324 else if(autocvar_g_nexball_football_physics == 2) // 2nd mod try: totally independant. Really playable!
325 {
326 makevectors(toucher.v_angle.y * '0 1 0');
328 }
329 else // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
330 {
331 makevectors(toucher.v_angle);
333 }
334 this.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
335}
336
338{
339 if(toucher.ballcarried)
340 {
341 football_touch(this, toucher);
342 return;
343 }
344 // TODO: mutator hook to prevent picking up objectives
346 {
347 if(GetResource(toucher, RES_HEALTH) < 1)
348 return;
349 LogNB("caught", toucher);
350 GiveBall(toucher, this);
351 }
352 else if(toucher.solid == SOLID_BSP)
353 {
355 if(this.velocity && !this.cnt)
357 }
358}
359
361{
362 entity ball;
363 float isclient, pscore, otherteam;
364 string pname;
365
366 if(game_stopped) return;
367 if((this.spawnflags & GOAL_TOUCHPLAYER) && toucher.ballcarried)
368 ball = toucher.ballcarried;
369 else
370 ball = toucher;
371 if(ball.classname != "nexball_basketball")
372 if(ball.classname != "nexball_football")
373 return;
374 if((!ball.pusher && this.team != GOAL_OUT) || ball.cnt)
375 return;
377
378
379 if(NumTeams(nb_teams) == 2)
380 otherteam = OtherTeam(ball.team);
381 else
382 otherteam = 0;
383
384 if((isclient = IS_CLIENT(ball.pusher)))
385 pname = ball.pusher.netname;
386 else
387 pname = "Someone (?)";
388
389 if(ball.team == this.team) //owngoal (regular goals)
390 {
391 LogNB("owngoal", ball.pusher);
392 bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
393 pscore = -1;
394 }
395 else if(this.team == GOAL_FAULT)
396 {
397 LogNB("fault", ball.pusher);
398 if(NumTeams(nb_teams) == 2)
399 bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
400 else
401 bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
402 pscore = -1;
403 }
404 else if(this.team == GOAL_OUT)
405 {
406 LogNB("out", ball.pusher);
407 if((this.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
408 bprint(pname, "^7 went out of bounds.\n");
409 else
410 bprint("The ball was returned.\n");
411 pscore = 0;
412 }
413 else //score
414 {
415 LogNB(strcat("goal:", ftos(this.team)), ball.pusher);
416 bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
417 pscore = 1;
418 }
419
421
422 if(ball.team && pscore)
423 {
424 if(NumTeams(nb_teams) == 2 && pscore < 0)
425 TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
426 else
427 TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
428 }
429 if(isclient)
430 {
431 if(pscore > 0)
432 GameRules_scoring_add(ball.pusher, NEXBALL_GOALS, pscore);
433 else if(pscore < 0)
434 GameRules_scoring_add(ball.pusher, NEXBALL_FAULTS, -pscore);
435 }
436
437 if(ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER
438 DropBall(ball, ball.owner.origin, ball.owner.velocity);
439
440 WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
441
442 ball.cnt = 1;
443 setthink(ball, ResetBall);
444 if(ball.classname == "nexball_basketball")
445 settouch(ball, football_touch); // better than func_null: football control until the ball gets reset
446 ball.nextthink = time + autocvar_g_nexball_delay_goal * (this.team != GOAL_OUT);
447}
448
449//=======================//
450// team ents //
451//=======================//
452spawnfunc(nexball_team)
453{
454 if(!g_nexball)
455 {
456 delete(this);
457 return;
458 }
459 this.team = this.cnt + 1;
460}
461
462void nb_spawnteam(string teamname, float teamcolor)
463{
464 LOG_TRACE("^2spawned team ", teamname);
465 entity e = new_pure(nexball_team);
466 e.netname = teamname;
467 e.cnt = teamcolor;
468 e.team = e.cnt + 1;
469 //nb_teams += 1;
470}
471
473{
474 bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
475 entity e;
476 for(e = NULL; (e = find(e, classname, "nexball_goal"));)
477 {
478 switch(e.team)
479 {
480 case NUM_TEAM_1:
481 if(!t_red)
482 {
483 nb_spawnteam("Red", e.team-1) ;
484 nb_teams |= BIT(0);
485 t_red = true;
486 }
487 break;
488 case NUM_TEAM_2:
489 if(!t_blue)
490 {
491 nb_spawnteam("Blue", e.team-1) ;
492 t_blue = true;
493 nb_teams |= BIT(1);
494 }
495 break;
496 case NUM_TEAM_3:
497 if(!t_yellow)
498 {
499 nb_spawnteam("Yellow", e.team-1);
500 t_yellow = true;
501 nb_teams |= BIT(2);
502 }
503 break;
504 case NUM_TEAM_4:
505 if(!t_pink)
506 {
507 nb_spawnteam("Pink", e.team-1) ;
508 t_pink = true;
509 nb_teams |= BIT(3);
510 }
511 break;
512 }
513 }
514}
515
517{
518 if(find(NULL, classname, "nexball_team") == NULL)
521}
522
523
524//=======================//
525// spawnfuncs //
526//=======================//
527
529{
530 if(!g_nexball) { delete(this); return; }
531
532// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
533
534 if(this.model == "")
535 {
536 this.model = "models/nexball/ball.md3";
537 this.scale = 1.3;
538 }
539
540 precache_model(this.model);
541 _setmodel(this, this.model);
542 setsize(this, BALL_MINS, BALL_MAXS);
543 ball_scale = this.scale;
544
545 relocate_nexball(this);
546 this.spawnorigin = this.origin;
547
548 this.effects = this.effects | EF_LOWPRECISION;
549
550 if(cvar(strcat("g_", this.classname, "_trail"))) //nexball_basketball :p
551 {
553 this.glow_trail = true;
554 }
555
557
560
562 this.noise = "";
563 else if(this.noise == "")
564 this.noise = strzone(SND(NB_BOUNCE));
565 //bounce sound placeholder (FIXME)
566 if(this.noise1 == "")
567 this.noise1 = strzone(SND(NB_DROP));
568 //ball drop sound placeholder (FIXME)
569 if(this.noise2 == "")
570 this.noise2 = strzone(SND(NB_STEAL));
571 //stealing sound placeholder (FIXME)
572 if(this.noise) precache_sound(this.noise);
575
576 WaypointSprite_AttachCarrier(WP_NbBall, this, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
577
578 this.reset = ball_restart;
579 setthink(this, InitBall);
581}
582
583spawnfunc(nexball_basketball)
584{
586 if (!(balls & BALL_BASKET))
587 {
588 /*
589 CVTOV(g_nexball_basketball_effects_default);
590 CVTOV(g_nexball_basketball_delay_hold);
591 CVTOV(g_nexball_basketball_delay_hold_forteam);
592 CVTOV(g_nexball_basketball_teamsteal);
593 */
595 }
596 if(!this.effects)
598 this.solid = SOLID_TRIGGER;
603 SpawnBall(this);
604}
605
616
618{
620 entity wp_owner = this.owner;
621 if(SAME_TEAM(e, wp_owner)) { return false; }
622
623 return true;
624}
625
627{
628 if(!g_nexball) { delete(this); return; }
629
631
632 if(this.team != GOAL_OUT && Team_IsValidTeam(this.team))
633 {
634 entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (this.absmin + this.absmax) * 0.5, this, sprite, RADARICON_NONE);
635 wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 0.5 0');
637 }
638
639 this.classname = "nexball_goal";
640 if(this.noise == "")
641 this.noise = "ctf/respawn.wav";
642 precache_sound(this.noise);
643 settouch(this, GoalTouch);
644}
645
646spawnfunc(nexball_redgoal)
647{
648 this.team = NUM_TEAM_1;
649 SpawnGoal(this);
650}
651spawnfunc(nexball_bluegoal)
652{
653 this.team = NUM_TEAM_2;
654 SpawnGoal(this);
655}
656spawnfunc(nexball_yellowgoal)
657{
658 this.team = NUM_TEAM_3;
659 SpawnGoal(this);
660}
661spawnfunc(nexball_pinkgoal)
662{
663 this.team = NUM_TEAM_4;
664 SpawnGoal(this);
665}
666
667spawnfunc(nexball_fault)
668{
669 this.team = GOAL_FAULT;
670 if(this.noise == "")
671 this.noise = strzone(SND(TYPEHIT));
672 SpawnGoal(this);
673}
674
675spawnfunc(nexball_out)
676{
677 this.team = GOAL_OUT;
678 if(this.noise == "")
679 this.noise = strzone(SND(TYPEHIT));
680 SpawnGoal(this);
681}
682
683//
684//Spawnfuncs preserved for compatibility
685//
686
688{
689 spawnfunc_nexball_football(this);
690}
691spawnfunc(ball_football)
692{
693 spawnfunc_nexball_football(this);
694}
695spawnfunc(ball_basketball)
696{
697 spawnfunc_nexball_basketball(this);
698}
699// The "red goal" is defended by blue team. A ball in there counts as a point for red.
700spawnfunc(ball_redgoal)
701{
702 spawnfunc_nexball_bluegoal(this); // I blame Revenant
703}
704spawnfunc(ball_bluegoal)
705{
706 spawnfunc_nexball_redgoal(this); // but he didn't mean to cause trouble :p
707}
708spawnfunc(ball_fault)
709{
710 spawnfunc_nexball_fault(this);
711}
712spawnfunc(ball_bound)
713{
714 spawnfunc_nexball_out(this);
715}
716
717bool ball_customize(entity this, entity client)
718{
719 if(!this.owner)
720 {
721 this.effects &= ~EF_FLAME;
722 this.scale = 1;
723 setcefc(this, func_null);
724 return true;
725 }
726
727 if(client == this.owner)
728 {
730 if(this.enemy)
731 this.effects |= EF_FLAME;
732 else
733 this.effects &= ~EF_FLAME;
734 }
735 else
736 {
737 this.effects &= ~EF_FLAME;
738 this.scale = 1;
739 }
740
741 return true;
742}
743
744void nb_DropBall(entity player)
745{
746 if(player.ballcarried && g_nexball)
747 DropBall(player.ballcarried, player.origin, player.velocity);
748}
749
751{
752 entity player = M_ARGV(0, entity);
753
754 nb_DropBall(player);
755}
756
757MUTATOR_HOOKFUNCTION(nb, PlayerDies)
758{
760
762}
763
764MUTATOR_HOOKFUNCTION(nb, MakePlayerObserver)
765{
766 entity player = M_ARGV(0, entity);
767
768 nb_DropBall(player);
769 return false;
770}
771
773{
774 entity player = M_ARGV(0, entity);
775
776 makevectors(player.v_angle);
778 {
779 if(player.ballcarried)
780 {
781 // 'view ball'
782 player.ballcarried.velocity = player.velocity;
783 setcefc(player.ballcarried, ball_customize);
784
785 vector org = player.origin + player.view_ofs +
789 setorigin(player.ballcarried, org);
790
791 // 'safe passing'
793 {
794 if(player.ballcarried.wait < time && player.ballcarried.enemy)
795 {
796 //centerprint(player, sprintf("Lost lock on %s", player.ballcarried.enemy.netname));
797 player.ballcarried.enemy = NULL;
798 }
799
800
801 //tracebox(player.origin + player.view_ofs, '-2 -2 -2', '2 2 2', player.origin + player.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
802 crosshair_trace(player);
803 if( trace_ent &&
805 !IS_DEAD(trace_ent) &&
806 trace_ent.team == player.team &&
807 vdist(trace_ent.origin - player.origin, <=, autocvar_g_nexball_safepass_maxdist) )
808 {
809
810 //if(player.ballcarried.enemy != trace_ent)
811 // centerprint(player, sprintf("Locked to %s", trace_ent.netname));
812 player.ballcarried.enemy = trace_ent;
813 player.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
814
815
816 }
817 }
818 }
819 else
820 {
821 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
822 {
823 .entity weaponentity = weaponentities[slot];
824
825 if(STAT(WEAPONS, player.(weaponentity)))
826 {
827 STAT(WEAPONS, player) = STAT(WEAPONS, player.(weaponentity));
828 Weapon w = WEP_NEXBALL;
829 w.wr_resetplayer(w, player);
830 player.(weaponentity).m_switchweapon = player.m_switchweapon;
831 W_SwitchWeapon(player, player.(weaponentity).m_switchweapon, weaponentity);
832
833 STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
834 }
835 }
836 }
837
838 }
839
840 nexball_setstatus(player);
841}
842
844{
845 entity spectatee = M_ARGV(0, entity);
846 entity client = M_ARGV(1, entity);
847
848 STAT(NB_METERSTART, client) = STAT(NB_METERSTART, spectatee);
849}
850
851MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
852{
853 entity player = M_ARGV(0, entity);
854
855 STAT(NB_METERSTART, player) = 0;
856 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
857 {
858 .entity weaponentity = weaponentities[slot];
859 STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
860 }
861
863 STAT(WEAPONS, player) |= WEPSET(NEXBALL);
864 else
865 STAT(WEAPONS, player) = '0 0 0';
866
867 return false;
868}
869
870MUTATOR_HOOKFUNCTION(nb, PlayerPhysics_UpdateStats)
871{
872 entity player = M_ARGV(0, entity);
873 // these automatically reset, no need to worry
874
875 if(player.ballcarried)
876 STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_nexball_basketball_carrier_highspeed;
877}
878
879MUTATOR_HOOKFUNCTION(nb, ForbidThrowCurrentWeapon)
880{
881 //entity player = M_ARGV(0, entity);
882 entity wepent = M_ARGV(1, entity);
883
884 return wepent.m_weapon == WEP_NEXBALL;
885}
886
887MUTATOR_HOOKFUNCTION(nb, ForbidDropCurrentWeapon)
888{
889 //entity player = M_ARGV(0, entity);
890 int wep = M_ARGV(1, int);
891
892 return wep == WEP_MORTAR.m_id; // TODO: what is this for?
893}
894
895MUTATOR_HOOKFUNCTION(nb, FilterItem)
896{
897 entity item = M_ARGV(0, entity);
898
899 if(ITEM_IS_LOOT(item))
900 if(item.weapon == WEP_NEXBALL.m_id)
901 return true;
902
903 return false;
904}
905
907{
908 entity item = M_ARGV(0, entity);
910
911 if(item.weapon && toucher.ballcarried)
912 return MUT_ITEMTOUCH_RETURN; // no new weapons for you, mister!
913
915}
916
918{
919 M_ARGV(1, string) = "nexball_team";
920 return true;
921}
922
923MUTATOR_HOOKFUNCTION(nb, WantWeapon)
924{
925 M_ARGV(1, float) = 0; // weapon is set a few lines later, apparently
926 return true;
927}
928
929MUTATOR_HOOKFUNCTION(nb, DropSpecialItems)
930{
932
933 if(frag_target.ballcarried)
934 DropBall(frag_target.ballcarried, frag_target.origin, frag_target.velocity);
935
936 return false;
937}
938
939MUTATOR_HOOKFUNCTION(nb, SendWaypoint)
940{
941 M_ARGV(2, int) &= ~0x80;
942}
943
945{
948 g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
949 g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
950
951 // General settings
952 /*
953 CVTOV(g_nexball_football_boost_forward); //100
954 CVTOV(g_nexball_football_boost_up); //200
955 CVTOV(g_nexball_delay_idle); //10
956 CVTOV(g_nexball_football_physics); //0
957 */
959
960 GameRules_teams(true);
963
965}
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:335
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition weapon.qh:44
virtual void wr_resetplayer()
(SERVER) clears fields that the weapon may use
Definition weapon.qh:106
float lifetime
Definition powerups.qc:23
float cnt
Definition powerups.qc:24
bool pushable
Definition items.qc:14
entity owner
Definition main.qh:87
int team
Definition main.qh:188
entity teams
Definition main.qh:58
int spawnflags
Definition ammo.qh:15
#define M_ARGV(x, type)
Definition events.qh:17
#define IS_CLIENT(s)
Definition player.qh:242
#define IS_DEAD(s)
Definition player.qh:245
float lastground
Definition player.qh:64
#define IS_PLAYER(s)
Definition player.qh:243
const int SFL_LOWER_IS_BETTER
Lower scores are better (e.g.
Definition scores.qh:102
const int SFL_SORT_PRIO_SECONDARY
Scoring priority (NOTE: PRIMARY is used for fraglimit) NOTE: SFL_SORT_PRIO_SECONDARY value must be lo...
Definition scores.qh:133
const int SFL_SORT_PRIO_PRIMARY
Definition scores.qh:134
float game_starttime
Definition stats.qh:82
float game_stopped
Definition stats.qh:81
const int INITPRIO_GAMETYPE
Definition constants.qh:94
vector v_up
string classname
entity trace_ent
const float SOLID_TRIGGER
float DPCONTENTS_SOLID
vector avelocity
vector velocity
float DPCONTENTS_BODY
float effects
float DPCONTENTS_PLAYERCLIP
float time
vector v_right
float trace_startsolid
const float EF_FLAME
float nextthink
vector absmax
vector v_forward
vector origin
vector absmin
const float EF_NOSHADOW
const float SOLID_BSP
float dphitcontentsmask
int state
float EF_LOWPRECISION
float glow_trail
float glow_color
model
Definition ent_cs.qc:139
solid
Definition ent_cs.qc:165
bool radar_showenemies
Definition ent_cs.qh:50
void GameLogEcho(string s)
Definition gamelog.qc:15
bool autocvar_sv_eventlog
Definition gamelog.qh:3
#define ITEM_IS_LOOT(item)
Returns whether the item is loot.
Definition spawning.qh:39
entity pusher
Definition laser.qc:57
#define PlayerPreThink
Definition _all.inc:254
#define ClientDisconnect
Definition _all.inc:242
#define STAT(...)
Definition stats.qh:82
#define EXACTTRIGGER_TOUCH(e, t)
Definition common.qh:115
#define EXACTTRIGGER_INIT
Definition common.qh:116
#define move_out_of_solid(e)
Definition common.qh:110
#define LOG_TRACE(...)
Definition log.qh:76
#define LOG_INFOF(...)
Definition log.qh:66
float cvar(string name)
entity find(entity start,.string field, string match)
void bprint(string text,...)
string precache_sound(string sample)
string vtos(vector v)
float min(float f,...)
float rint(float f)
string ftos(float f)
string strzone(string s)
float max(float f,...)
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_NONE
Definition movetypes.qh:129
float bouncefactor
Definition movetypes.qh:47
#define UNSET_ONGROUND(s)
Definition movetypes.qh:18
const int MOVETYPE_NOCLIP
Definition movetypes.qh:137
const int MOVETYPE_FLY
Definition movetypes.qh:134
float bouncestop
Definition movetypes.qh:46
const int MOVETYPE_BOUNCE
Definition movetypes.qh:139
const int NB_CARRYING
Definition nexball.qh:36
#define g_nexball
Definition nexball.qh:33
var void func_null()
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1573
#define APP_TEAM_NUM(num, prefix)
Definition all.qh:84
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:67
#define NULL
Definition post.qh:14
#define makevectors
Definition post.qh:21
#define objerror
Definition pre.qh:8
float scale
Definition projectile.qc:14
float TeamScore_AddToTeam(int t, float scorefield, float score)
Adds a score to the given team.
Definition scores.qc:107
int NumTeams(int teams)
bool W_SwitchWeapon(entity this, Weapon w,.entity weaponentity)
Definition selection.qc:275
#define setthink(e, f)
vector
Definition self.qh:92
#define setcefc(e, f)
vector org
Definition self.qh:92
entity entity toucher
Definition self.qh:72
#define settouch(e, f)
Definition self.qh:73
void SpectateCopy(entity this, entity spectatee)
Definition client.qc:1793
@ MUT_ITEMTOUCH_RETURN
Definition events.qh:735
@ MUT_ITEMTOUCH_CONTINUE
Definition events.qh:734
const int CH_TRIGGER
Definition sound.qh:12
const float VOL_BASE
Definition sound.qh:36
const float ATTEN_NONE
Definition sound.qh:27
#define _sound(e, c, s, v, a)
Definition sound.qh:43
const float ATTEN_NORM
Definition sound.qh:30
#define SND(id)
Definition all.qh:35
#define spawnfunc(id)
Definition spawnfunc.qh:96
string noise
Definition subs.qh:83
string noise1
Definition subs.qh:83
string noise2
Definition subs.qh:83
entity sprite
Definition sv_assault.qc:11
entity frag_target
Definition sv_ctf.qc:2321
entity enemy
Definition sv_ctf.qh:153
entity ballcarried
void nexball_setstatus(entity this)
Definition sv_nexball.qc:95
int autocvar_g_nexball_trail_color
Definition sv_nexball.qc:31
float autocvar_g_nexball_basketball_meter_minpower
Definition sv_nexball.qc:22
const int NBM_BASKETBALL
Definition sv_nexball.qc:55
void nb_DropBall(entity player)
bool autocvar_g_nexball_playerclip_collisions
Definition sv_nexball.qc:32
float OtherTeam(float t)
Definition sv_nexball.qc:58
void relocate_nexball(entity this)
float autocvar_g_balance_nexball_primary_refire
Definition sv_nexball.qc:42
bool autocvar_g_nexball_radar_showallplayers
Definition sv_nexball.qc:29
float autocvar_g_nexball_football_bouncestop
Definition sv_nexball.qc:28
void nb_spawnteam(string teamname, float teamcolor)
float autocvar_g_nexball_delay_goal
Definition sv_nexball.qc:24
const int ST_NEXBALL_GOALS
Definition sv_nexball.qc:67
bool autocvar_g_nexball_basketball_meter
Definition sv_nexball.qc:20
float autocvar_g_balance_nexball_secondary_refire
Definition sv_nexball.qc:47
void GoalTouch(entity this, entity toucher)
float autocvar_g_nexball_basketball_meter_maxpower
Definition sv_nexball.qc:21
void LogNB(string mode, entity actor)
Definition sv_nexball.qc:77
float autocvar_g_balance_nexball_primary_animtime
Definition sv_nexball.qc:41
void SpawnGoal(entity this)
float nexball_mode
Definition sv_nexball.qc:56
float autocvar_g_nexball_delay_collect
Definition sv_nexball.qc:23
void InitBall(entity this)
float autocvar_g_nexball_basketball_bouncestop
Definition sv_nexball.qc:18
bool nb_Goal_Customize(entity this, entity client)
const int NBM_NONE
Definition sv_nexball.qc:53
void football_touch(entity this, entity toucher)
float autocvar_g_balance_nexball_secondary_lifetime
Definition sv_nexball.qc:46
const int NBM_FOOTBALL
Definition sv_nexball.qc:54
float autocvar_g_balance_nexball_secondary_speed
Definition sv_nexball.qc:48
void ball_restart(entity this)
Definition sv_nexball.qc:88
void GiveBall(entity plyr, entity ball)
float autocvar_g_nexball_basketball_carrier_highspeed
Definition sv_nexball.qc:19
float autocvar_g_balance_nexball_primary_speed
Definition sv_nexball.qc:43
float autocvar_g_nexball_delay_start
Definition sv_nexball.qc:25
float autocvar_g_nexball_football_bouncefactor
Definition sv_nexball.qc:27
void basketball_touch(entity this, entity toucher)
vector autocvar_g_nexball_viewmodel_offset
Definition sv_nexball.qc:39
float autocvar_g_nexball_safepass_holdtime
Definition sv_nexball.qc:36
bool autocvar_g_nexball_basketball_jumppad
Definition sv_nexball.qc:16
float autocvar_g_nexball_safepass_maxdist
Definition sv_nexball.qc:35
float autocvar_g_nexball_safepass_turnrate
Definition sv_nexball.qc:34
bool autocvar_g_nexball_sound_bounce
Definition sv_nexball.qc:30
bool autocvar_g_nexball_football_jumppad
Definition sv_nexball.qc:26
void nb_ScoreRules(int teams)
Definition sv_nexball.qc:68
float autocvar_g_balance_nexball_secondary_force
Definition sv_nexball.qc:45
float autocvar_g_nexball_basketball_bouncefactor
Definition sv_nexball.qc:17
float autocvar_g_nexball_tackling
Definition sv_nexball.qc:38
int autocvar_g_nexball_goalleadlimit
Definition sv_nexball.qc:13
void DropBall(entity ball, vector org, vector vel)
float autocvar_g_nexball_viewmodel_scale
Definition sv_nexball.qc:37
bool ball_customize(entity this, entity client)
void nb_delayedinit(entity this)
void nb_Initialize()
float autocvar_g_nexball_goallimit
Definition sv_nexball.qc:14
void ResetBall(entity this)
void nb_spawnteams()
float autocvar_g_balance_nexball_secondary_animtime
Definition sv_nexball.qc:44
void SpawnBall(entity this)
void DropOwner(entity this)
float ball_scale
Definition sv_nexball.qh:48
const vector BALL_MAXS
Definition sv_nexball.qh:26
float autocvar_g_nexball_basketball_effects_default
Definition sv_nexball.qh:43
float nb_teams
Definition sv_nexball.qh:49
float autocvar_g_nexball_delay_idle
Definition sv_nexball.qh:40
const float BALL_BASKET
Definition sv_nexball.qh:29
float g_nexball_meter_period
Definition sv_nexball.qh:54
float balls
Definition sv_nexball.qh:47
const float BALL_FOOT
Definition sv_nexball.qh:28
float autocvar_g_nexball_meter_period
Definition sv_nexball.qh:45
const float GOAL_OUT
Definition sv_nexball.qh:34
float autocvar_g_nexball_football_physics
Definition sv_nexball.qh:39
float autocvar_g_nexball_basketball_delay_hold_forteam
Definition sv_nexball.qh:42
entity nb_dropper
Definition sv_nexball.qh:51
const float GOAL_FAULT
Definition sv_nexball.qh:33
float autocvar_g_nexball_football_boost_forward
Definition sv_nexball.qh:37
float autocvar_g_nexball_football_boost_up
Definition sv_nexball.qh:38
const float GOAL_TOUCHPLAYER
Definition sv_nexball.qh:31
float nb_droptime
Definition sv_nexball.qh:52
const vector BALL_MINS
Definition sv_nexball.qh:25
float autocvar_g_nexball_basketball_delay_hold
Definition sv_nexball.qh:41
const float BALL_EFFECTMASK
Definition sv_nexball.qh:24
void GameRules_limit_score(int limit)
Definition sv_rules.qc:23
void GameRules_teams(bool value)
Definition sv_rules.qc:3
void GameRules_limit_lead(int limit)
Definition sv_rules.qc:33
#define GameRules_scoring_vip(player, value)
Definition sv_rules.qh:78
#define GameRules_scoring_add(client, fld, value)
Definition sv_rules.qh:85
#define GameRules_scoring(teams, spprio, stprio, fields)
Definition sv_rules.qh:58
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:459
bool Team_IsValidTeam(int team_num)
Returns whether team value is valid.
Definition teams.qh:133
#define SAME_TEAM(a, b)
Definition teams.qh:241
const int NUM_TEAM_2
Definition teams.qh:14
const int NUM_TEAM_4
Definition teams.qh:16
vector Team_ColorRGB(int teamid)
Definition teams.qh:76
const int NUM_TEAM_3
Definition teams.qh:15
#define Team_ColoredFullName(teamid)
Definition teams.qh:232
const int NUM_TEAM_1
Definition teams.qh:13
void crosshair_trace(entity pl)
Definition tracing.qc:549
#define IS_VEHICLE(v)
Definition utils.qh:22
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition vector.qh:8
void WaypointSprite_Kill(entity wp)
void WaypointSprite_Ping(entity e)
entity WaypointSprite_Spawn(entity spr, float _lifetime, float maxdistance, entity ref, vector ofs, entity showto, float t, entity own,.entity ownfield, float hideable, entity icon)
entity WaypointSprite_getviewentity(entity e)
entity WaypointSprite_AttachCarrier(entity spr, entity carrier, entity icon)
entity WaypointSprite_SpawnFixed(entity spr, vector ofs, entity own,.entity ownfield, entity icon)
void WaypointSprite_UpdateRule(entity e, float t, float r)
const int SPRITERULE_DEFAULT
entity waypointsprite_attachedforcarrier
#define WEPSET(id)
Definition all.qh:45
vector spawnorigin
Definition all.qh:391
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
const int WS_READY
idle frame
Definition weapon.qh:41
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17
Weapon m_weapon
Definition wepent.qh:26
Weapon m_switchweapon
Definition wepent.qh:25
void InitializeEntity(entity e, void(entity this) func, int order)
Definition world.qc:2209