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 = find(NULL, classname, "nexball_team");
61 if(e.team == t)
62 e = find(e, classname, "nexball_team");
63 return e.team;
64}
65
66const int ST_NEXBALL_GOALS = 1;
68{
70 field_team(ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
71 field(SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
72 field(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
73 });
74}
75
76void LogNB(string mode, entity actor)
77{
78 string s;
80 return;
81 s = strcat(":nexball:", mode);
82 if(actor != NULL)
83 s = strcat(s, ":", ftos(actor.playerid));
84 GameLogEcho(s);
85}
86
88{
89 if(this.owner)
90 DropBall(this, this.owner.origin, '0 0 0');
91 ResetBall(this);
92}
93
95{
96 STAT(OBJECTIVE_STATUS, this) &= ~NB_CARRYING;
97 if(this.ballcarried)
98 {
99 if(this.ballcarried.lifetime && (this.ballcarried.lifetime < time))
100 {
101 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
102 entity e = this.ballcarried;
103 DropBall(this.ballcarried, this.ballcarried.owner.origin, '0 0 0');
104 ResetBall(e);
105 }
106 else
107 STAT(OBJECTIVE_STATUS, this) |= NB_CARRYING;
108 }
109}
110
112{
113 tracebox(this.origin, BALL_MINS, BALL_MAXS, this.origin, true, this);
115 {
116 vector o = this.origin;
117 if (!move_out_of_solid(this)) {
118 objerror(this, "could not get out of solid at all!");
119 }
120 LOG_INFOF(
121 "^1NOTE: this map needs FIXING. %s at %s needs to be moved out of solid, e.g. by %s",
122 this.classname,
123 vtos(o - '0 0 1'),
124 vtos(this.origin - o)
125 );
126 this.origin = o;
127 }
128}
129
131{
132 entity ownr = this.owner;
133 DropBall(this, ownr.origin, ownr.velocity);
134 makevectors(ownr.v_angle.y * '0 1 0');
135 ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
136 UNSET_ONGROUND(ownr);
137}
138
139void GiveBall(entity plyr, entity ball)
140{
141 .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
142 entity ownr = ball.owner;
143 if(ownr)
144 {
146 ownr.ballcarried = NULL;
147 GameRules_scoring_vip(ownr, false);
148 if(STAT(NB_METERSTART, ownr))
149 {
150 STAT(NB_METERSTART, ownr) = 0;
151 ownr.(weaponentity).state = WS_READY;
152 }
153 WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
154 }
155 else
156 {
157 WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
158 }
159
160 //setattachment(ball, plyr, "");
161 setorigin(ball, plyr.origin + plyr.view_ofs);
162
163 if(ball.team != plyr.team)
165
166 ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
167 ball.weaponentity_fld = weaponentity;
168 ball.team = plyr.team;
169 plyr.ballcarried = ball;
170 GameRules_scoring_vip(plyr, true);
171 ball.nb_dropper = plyr;
172
175
176 ball.velocity = '0 0 0';
178 settouch(ball, func_null);
179 ball.effects |= EF_NOSHADOW;
180 ball.scale = 1; // scale down.
181
182 WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
183 WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
184
186 {
187 setthink(ball, DropOwner);
189 }
190
191 STAT(WEAPONS, plyr.(weaponentity)) = STAT(WEAPONS, plyr);
192 plyr.m_switchweapon = plyr.(weaponentity).m_weapon;
193 STAT(WEAPONS, plyr) = WEPSET(NEXBALL);
194 Weapon w = WEP_NEXBALL;
195 w.wr_resetplayer(w, plyr);
196 plyr.(weaponentity).m_switchweapon = WEP_NEXBALL;
197 W_SwitchWeapon(plyr, WEP_NEXBALL, weaponentity);
198}
199
201{
203 ball.effects &= ~EF_NOSHADOW;
205
206 setattachment(ball, NULL, "");
207 setorigin(ball, org);
209 UNSET_ONGROUND(ball);
210 ball.scale = ball_scale;
211 ball.velocity = vel;
212 ball.nb_droptime = time;
214 setthink(ball, ResetBall);
215 ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.lifetime);
216
217 if(STAT(NB_METERSTART, ball.owner))
218 {
219 STAT(NB_METERSTART, ball.owner) = 0;
220 .entity weaponentity = ball.weaponentity_fld;
221 ball.owner.(weaponentity).state = WS_READY;
222 }
223
224 WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
225 WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
226 WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
227
228 entity e = ball.owner; ball.owner = NULL;
229 e.ballcarried = NULL;
230 GameRules_scoring_vip(e, false);
231}
232
233void InitBall(entity this)
234{
235 if(game_stopped) return;
236 UNSET_ONGROUND(this);
238 if(this.classname == "nexball_basketball")
240 else if(this.classname == "nexball_football")
242 this.cnt = 0;
243 setthink(this, ResetBall);
245 this.lifetime = 0;
246 this.pusher = NULL;
247 this.team = false;
250 LogNB("init", NULL);
251}
252
254{
255 if(this.cnt < 2) // step 1
256 {
257 if(time == this.lifetime)
258 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
259
260 settouch(this, func_null);
262 this.velocity = '0 0 0'; // just in case?
263 if(!this.cnt)
264 LogNB("resetidle", NULL);
265 this.cnt = 2;
266 this.nextthink = time;
267 }
268 else if(this.cnt < 4) // step 2 and 3
269 {
270// dprint("Step ", ftos(this.cnt), ": Calculated velocity: ", vtos(this.spawnorigin - this.origin), ", time: ", ftos(time), "\n");
271 this.velocity = (this.spawnorigin - this.origin) * (this.cnt - 1); // 1 or 0.5 second movement
272 this.nextthink = time + 0.5;
273 this.cnt += 1;
274 }
275 else // step 4
276 {
277// dprint("Step 4: time: ", ftos(time), "\n");
278 if(vdist(this.origin - this.spawnorigin, >, 10)) // should not happen anymore
279 LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
280 vtos(this.origin - this.spawnorigin), " Velocity: ", vtos(this.velocity), "\n");
281 this.velocity = '0 0 0';
282 setorigin(this, this.spawnorigin); // make sure it's positioned correctly anyway
284 setthink(this, InitBall);
286 }
287}
288
290{
291 if(toucher.solid == SOLID_BSP)
292 {
293 if(time > this.lastground + 0.1)
294 {
296 this.lastground = time;
297 }
298 if(this.velocity && !this.cnt)
300 return;
301 }
303 return;
304 if(GetResource(toucher, RES_HEALTH) < 1)
305 return;
306 if(!this.cnt)
308
309 this.pusher = toucher;
310 this.team = toucher.team;
311
312 if(autocvar_g_nexball_football_physics == -1) // MrBougo try 1, before decompiling Rev's original
313 {
314 if(toucher.velocity)
315 this.velocity = toucher.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
316 }
317 else if(autocvar_g_nexball_football_physics == 1) // MrBougo's modded Rev style: partially independant of the height of the aiming point
318 {
319 makevectors(toucher.v_angle);
321 }
322 else if(autocvar_g_nexball_football_physics == 2) // 2nd mod try: totally independant. Really playable!
323 {
324 makevectors(toucher.v_angle.y * '0 1 0');
326 }
327 else // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
328 {
329 makevectors(toucher.v_angle);
331 }
332 this.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
333}
334
336{
337 if(toucher.ballcarried)
338 {
339 football_touch(this, toucher);
340 return;
341 }
342 // TODO: mutator hook to prevent picking up objectives
344 {
345 if(GetResource(toucher, RES_HEALTH) < 1)
346 return;
347 LogNB("caught", toucher);
348 GiveBall(toucher, this);
349 }
350 else if(toucher.solid == SOLID_BSP)
351 {
353 if(this.velocity && !this.cnt)
355 }
356}
357
359{
360 entity ball;
361 float isclient, pscore, otherteam;
362 string pname;
363
364 if(game_stopped) return;
365 if((this.spawnflags & GOAL_TOUCHPLAYER) && toucher.ballcarried)
366 ball = toucher.ballcarried;
367 else
368 ball = toucher;
369 if(ball.classname != "nexball_basketball")
370 if(ball.classname != "nexball_football")
371 return;
372 if((!ball.pusher && this.team != GOAL_OUT) || ball.cnt)
373 return;
375
376
377 if(NumTeams(nb_teams) == 2)
378 otherteam = OtherTeam(ball.team);
379 else
380 otherteam = 0;
381
382 if((isclient = IS_CLIENT(ball.pusher)))
383 pname = ball.pusher.netname;
384 else
385 pname = "Someone (?)";
386
387 if(ball.team == this.team) //owngoal (regular goals)
388 {
389 LogNB("owngoal", ball.pusher);
390 bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
391 pscore = -1;
392 }
393 else if(this.team == GOAL_FAULT)
394 {
395 LogNB("fault", ball.pusher);
396 if(NumTeams(nb_teams) == 2)
397 bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
398 else
399 bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
400 pscore = -1;
401 }
402 else if(this.team == GOAL_OUT)
403 {
404 LogNB("out", ball.pusher);
405 if((this.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
406 bprint(pname, "^7 went out of bounds.\n");
407 else
408 bprint("The ball was returned.\n");
409 pscore = 0;
410 }
411 else //score
412 {
413 LogNB(strcat("goal:", ftos(this.team)), ball.pusher);
414 bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
415 pscore = 1;
416 }
417
419
420 if(ball.team && pscore)
421 {
422 if(NumTeams(nb_teams) == 2 && pscore < 0)
423 TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
424 else
425 TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
426 }
427 if(isclient)
428 {
429 if(pscore > 0)
430 GameRules_scoring_add(ball.pusher, NEXBALL_GOALS, pscore);
431 else if(pscore < 0)
432 GameRules_scoring_add(ball.pusher, NEXBALL_FAULTS, -pscore);
433 }
434
435 if(ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER
436 DropBall(ball, ball.owner.origin, ball.owner.velocity);
437
438 WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
439
440 ball.cnt = 1;
441 setthink(ball, ResetBall);
442 if(ball.classname == "nexball_basketball")
443 settouch(ball, football_touch); // better than func_null: football control until the ball gets reset
444 ball.nextthink = time + autocvar_g_nexball_delay_goal * (this.team != GOAL_OUT);
445}
446
447//=======================//
448// team ents //
449//=======================//
450spawnfunc(nexball_team)
451{
452 if(!g_nexball)
453 {
454 delete(this);
455 return;
456 }
457 this.team = this.cnt + 1;
458}
459
460void nb_spawnteam(string teamname, float teamcolor)
461{
462 LOG_TRACE("^2spawned team ", teamname);
463 entity e = new_pure(nexball_team);
464 e.netname = teamname;
465 e.cnt = teamcolor;
466 e.team = e.cnt + 1;
467 //nb_teams += 1;
468}
469
471{
472 bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
473 for(entity e = NULL; (e = find(e, classname, "nexball_goal"));)
474 {
475 switch(e.team)
476 {
477 case NUM_TEAM_1:
478 if(!t_red)
479 {
480 nb_spawnteam("Red", e.team-1) ;
481 nb_teams |= BIT(0);
482 t_red = true;
483 }
484 break;
485 case NUM_TEAM_2:
486 if(!t_blue)
487 {
488 nb_spawnteam("Blue", e.team-1) ;
489 t_blue = true;
490 nb_teams |= BIT(1);
491 }
492 break;
493 case NUM_TEAM_3:
494 if(!t_yellow)
495 {
496 nb_spawnteam("Yellow", e.team-1);
497 t_yellow = true;
498 nb_teams |= BIT(2);
499 }
500 break;
501 case NUM_TEAM_4:
502 if(!t_pink)
503 {
504 nb_spawnteam("Pink", e.team-1) ;
505 t_pink = true;
506 nb_teams |= BIT(3);
507 }
508 break;
509 }
510 }
511}
512
514{
515 if(find(NULL, classname, "nexball_team") == NULL)
518}
519
520
521//=======================//
522// spawnfuncs //
523//=======================//
524
526{
527 if(!g_nexball) { delete(this); return; }
528
529// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
530
531 if(this.model == "")
532 {
533 this.model = "models/nexball/ball.md3";
534 this.scale = 1.3;
535 }
536
537 precache_model(this.model);
538 _setmodel(this, this.model);
539 setsize(this, BALL_MINS, BALL_MAXS);
540 ball_scale = this.scale;
541
542 relocate_nexball(this);
543 this.spawnorigin = this.origin;
544
545 this.effects |= EF_LOWPRECISION;
546
547 if(cvar(strcat("g_", this.classname, "_trail"))) //nexball_basketball :p
548 {
550 this.glow_trail = true;
551 }
552
554
557
559 this.noise = "";
560 else if(this.noise == "")
561 this.noise = strzone(SND(NB_BOUNCE));
562 //bounce sound placeholder (FIXME)
563 if(this.noise1 == "")
564 this.noise1 = strzone(SND(NB_DROP));
565 //ball drop sound placeholder (FIXME)
566 if(this.noise2 == "")
567 this.noise2 = strzone(SND(NB_STEAL));
568 //stealing sound placeholder (FIXME)
569 if(this.noise) precache_sound(this.noise);
572
573 WaypointSprite_AttachCarrier(WP_NbBall, this, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
574
575 this.reset = ball_restart;
576 setthink(this, InitBall);
578}
579
580spawnfunc(nexball_basketball)
581{
583 if (!(balls & BALL_BASKET))
584 {
585 /*
586 CVTOV(g_nexball_basketball_effects_default);
587 CVTOV(g_nexball_basketball_delay_hold);
588 CVTOV(g_nexball_basketball_delay_hold_forteam);
589 CVTOV(g_nexball_basketball_teamsteal);
590 */
592 }
593 if(!this.effects)
595 this.solid = SOLID_TRIGGER;
600 SpawnBall(this);
601}
602
613
615{
617 entity wp_owner = this.owner;
618 if(SAME_TEAM(e, wp_owner)) { return false; }
619
620 return true;
621}
622
624{
625 if(!g_nexball) { delete(this); return; }
626
628
629 if(this.team != GOAL_OUT && Team_IsValidTeam(this.team))
630 {
631 entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (this.absmin + this.absmax) * 0.5, this, sprite, RADARICON_NONE);
632 wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 0.5 0');
634 }
635
636 this.classname = "nexball_goal";
637 if(this.noise == "")
638 this.noise = "ctf/respawn.wav";
639 precache_sound(this.noise);
640 settouch(this, GoalTouch);
641}
642
643spawnfunc(nexball_redgoal)
644{
645 this.team = NUM_TEAM_1;
646 SpawnGoal(this);
647}
648spawnfunc(nexball_bluegoal)
649{
650 this.team = NUM_TEAM_2;
651 SpawnGoal(this);
652}
653spawnfunc(nexball_yellowgoal)
654{
655 this.team = NUM_TEAM_3;
656 SpawnGoal(this);
657}
658spawnfunc(nexball_pinkgoal)
659{
660 this.team = NUM_TEAM_4;
661 SpawnGoal(this);
662}
663
664spawnfunc(nexball_fault)
665{
666 this.team = GOAL_FAULT;
667 if(this.noise == "")
668 this.noise = strzone(SND(TYPEHIT));
669 SpawnGoal(this);
670}
671
672spawnfunc(nexball_out)
673{
674 this.team = GOAL_OUT;
675 if(this.noise == "")
676 this.noise = strzone(SND(TYPEHIT));
677 SpawnGoal(this);
678}
679
680//
681//Spawnfuncs preserved for compatibility
682//
683
685{
686 spawnfunc_nexball_football(this);
687}
688spawnfunc(ball_football)
689{
690 spawnfunc_nexball_football(this);
691}
692spawnfunc(ball_basketball)
693{
694 spawnfunc_nexball_basketball(this);
695}
696// The "red goal" is defended by blue team. A ball in there counts as a point for red.
697spawnfunc(ball_redgoal)
698{
699 spawnfunc_nexball_bluegoal(this); // I blame Revenant
700}
701spawnfunc(ball_bluegoal)
702{
703 spawnfunc_nexball_redgoal(this); // but he didn't mean to cause trouble :p
704}
705spawnfunc(ball_fault)
706{
707 spawnfunc_nexball_fault(this);
708}
709spawnfunc(ball_bound)
710{
711 spawnfunc_nexball_out(this);
712}
713
714bool ball_customize(entity this, entity client)
715{
716 if(!this.owner)
717 {
718 this.effects &= ~EF_FLAME;
719 this.scale = 1;
720 setcefc(this, func_null);
721 return true;
722 }
723
724 if(client == this.owner)
725 {
727 if(this.enemy)
728 this.effects |= EF_FLAME;
729 else
730 this.effects &= ~EF_FLAME;
731 }
732 else
733 {
734 this.effects &= ~EF_FLAME;
735 this.scale = 1;
736 }
737
738 return true;
739}
740
741void nb_DropBall(entity player)
742{
743 if(player.ballcarried && g_nexball)
744 DropBall(player.ballcarried, player.origin, player.velocity);
745}
746
748{
749 entity player = M_ARGV(0, entity);
750
751 nb_DropBall(player);
752}
753
754MUTATOR_HOOKFUNCTION(nb, PlayerDies)
755{
757
759}
760
761MUTATOR_HOOKFUNCTION(nb, MakePlayerObserver)
762{
763 entity player = M_ARGV(0, entity);
764
765 nb_DropBall(player);
766 return false;
767}
768
770{
771 entity player = M_ARGV(0, entity);
772
773 makevectors(player.v_angle);
775 {
776 if(player.ballcarried)
777 {
778 // 'view ball'
779 player.ballcarried.velocity = player.velocity;
780 setcefc(player.ballcarried, ball_customize);
781
782 vector org = player.origin + player.view_ofs +
786 setorigin(player.ballcarried, org);
787
788 // 'safe passing'
790 {
791 if(player.ballcarried.wait < time && player.ballcarried.enemy)
792 {
793 //centerprint(player, sprintf("Lost lock on %s", player.ballcarried.enemy.netname));
794 player.ballcarried.enemy = NULL;
795 }
796
797
798 //tracebox(player.origin + player.view_ofs, '-2 -2 -2', '2 2 2', player.origin + player.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
799 crosshair_trace(player);
800 if( trace_ent &&
802 !IS_DEAD(trace_ent) &&
803 trace_ent.team == player.team &&
804 vdist(trace_ent.origin - player.origin, <=, autocvar_g_nexball_safepass_maxdist) )
805 {
806
807 //if(player.ballcarried.enemy != trace_ent)
808 // centerprint(player, sprintf("Locked to %s", trace_ent.netname));
809 player.ballcarried.enemy = trace_ent;
810 player.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
811
812
813 }
814 }
815 }
816 else
817 {
818 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
819 {
820 .entity weaponentity = weaponentities[slot];
821
822 if(STAT(WEAPONS, player.(weaponentity)))
823 {
824 STAT(WEAPONS, player) = STAT(WEAPONS, player.(weaponentity));
825 Weapon w = WEP_NEXBALL;
826 w.wr_resetplayer(w, player);
827 player.(weaponentity).m_switchweapon = player.m_switchweapon;
828 W_SwitchWeapon(player, player.(weaponentity).m_switchweapon, weaponentity);
829
830 STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
831 }
832 }
833 }
834
835 }
836
837 nexball_setstatus(player);
838}
839
841{
842 entity spectatee = M_ARGV(0, entity);
843 entity client = M_ARGV(1, entity);
844
845 STAT(NB_METERSTART, client) = STAT(NB_METERSTART, spectatee);
846}
847
848MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
849{
850 entity player = M_ARGV(0, entity);
851
852 STAT(NB_METERSTART, player) = 0;
853 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
854 {
855 .entity weaponentity = weaponentities[slot];
856 STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
857 }
858
860 STAT(WEAPONS, player) |= WEPSET(NEXBALL);
861 else
862 STAT(WEAPONS, player) = '0 0 0';
863
864 return false;
865}
866
867MUTATOR_HOOKFUNCTION(nb, PlayerPhysics_UpdateStats)
868{
869 entity player = M_ARGV(0, entity);
870 // these automatically reset, no need to worry
871
872 if(player.ballcarried)
873 STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_nexball_basketball_carrier_highspeed;
874}
875
876MUTATOR_HOOKFUNCTION(nb, ForbidThrowCurrentWeapon)
877{
878 //entity player = M_ARGV(0, entity);
879 entity wepent = M_ARGV(1, entity);
880
881 return wepent.m_weapon == WEP_NEXBALL;
882}
883
884MUTATOR_HOOKFUNCTION(nb, ForbidDropCurrentWeapon)
885{
886 //entity player = M_ARGV(0, entity);
887 int wep = M_ARGV(1, int);
888
889 return wep == WEP_MORTAR.m_id; // TODO: what is this for?
890}
891
892MUTATOR_HOOKFUNCTION(nb, FilterItem)
893{
894 entity item = M_ARGV(0, entity);
895
896 if(ITEM_IS_LOOT(item))
897 if(item.weapon == WEP_NEXBALL.m_id)
898 return true;
899
900 return false;
901}
902
904{
905 entity item = M_ARGV(0, entity);
907
908 if(item.weapon && toucher.ballcarried)
909 return MUT_ITEMTOUCH_RETURN; // no new weapons for you, mister!
910
912}
913
915{
916 M_ARGV(1, string) = "nexball_team";
917 return true;
918}
919
920MUTATOR_HOOKFUNCTION(nb, WantWeapon)
921{
922 M_ARGV(1, float) = 0; // weapon is set a few lines later, apparently
923 return true;
924}
925
926MUTATOR_HOOKFUNCTION(nb, DropSpecialItems)
927{
929
930 if(frag_target.ballcarried)
931 DropBall(frag_target.ballcarried, frag_target.origin, frag_target.velocity);
932
933 return false;
934}
935
936MUTATOR_HOOKFUNCTION(nb, SendWaypoint)
937{
938 M_ARGV(2, int) &= ~0x80;
939}
940
942{
945 g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
946 g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
947
948 // General settings
949 /*
950 CVTOV(g_nexball_football_boost_forward); //100
951 CVTOV(g_nexball_football_boost_up); //200
952 CVTOV(g_nexball_delay_idle); //10
953 CVTOV(g_nexball_football_physics); //0
954 */
956
957 GameRules_teams(true);
960
962}
#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:42
virtual void wr_resetplayer()
(SERVER) clears fields that the weapon may use
Definition weapon.qh:130
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:241
#define IS_DEAD(s)
Definition player.qh:244
float lastground
Definition player.qh:64
#define IS_PLAYER(s)
Definition player.qh:242
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:108
int NumTeams(int teams)
bool W_SwitchWeapon(entity this, Weapon w,.entity weaponentity)
Definition selection.qc:265
#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:1794
@ 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:2314
entity enemy
Definition sv_ctf.qh:153
entity ballcarried
void nexball_setstatus(entity this)
Definition sv_nexball.qc:94
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:66
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:76
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:87
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:67
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:542
#define IS_VEHICLE(v)
Definition utils.qh:24
#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:47
vector spawnorigin
Definition all.qh:416
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
const int WS_READY
idle frame
Definition weapon.qh:38
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:2230