X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fgamemodes%2Fgamemode%2Fnexball%2Fnexball.qc;h=5a0ff2a2c22ade90150d22cad3fbcfdb8be07f3b;hb=refs%2Fmerge-requests%2F472%2Fhead;hp=9c6c9f0803941379bb39e765980cd4bc6361b133;hpb=06ac66a5edaa645e19ed9a6482409e8656a65b1d;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc b/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc index 9c6c9f080..5a0ff2a2c 100644 --- a/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc +++ b/qcsrc/common/gamemodes/gamemode/nexball/nexball.qc @@ -15,6 +15,8 @@ MUTATOR_HOOKFUNCTION(cl_nb, WantEventchase) #ifdef SVQC .float metertime = _STAT(NB_METERSTART); +.entity ballcarried; + int autocvar_g_nexball_goalleadlimit; #define autocvar_g_nexball_goallimit cvar("g_nexball_goallimit") @@ -34,6 +36,7 @@ float autocvar_g_nexball_football_bouncestop; bool autocvar_g_nexball_radar_showallplayers; bool autocvar_g_nexball_sound_bounce; int autocvar_g_nexball_trail_color; +bool autocvar_g_nexball_playerclip_collisions = true; float autocvar_g_nexball_safepass_turnrate; float autocvar_g_nexball_safepass_maxdist; @@ -68,14 +71,14 @@ float OtherTeam(float t) //works only if there are two teams on the map! return e.team; } -const float ST_NEXBALL_GOALS = 1; +const int ST_NEXBALL_GOALS = 1; void nb_ScoreRules(int teams) { - ScoreRules_basics(teams, 0, 0, true); - ScoreInfo_SetLabel_TeamScore( ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY); - ScoreInfo_SetLabel_PlayerScore( SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY); - ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER); - ScoreRules_basics_end(); + GameRules_scoring(teams, 0, 0, { + field_team(ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY); + field(SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY); + field(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER); + }); } void LogNB(string mode, entity actor) @@ -103,9 +106,9 @@ void nexball_setstatus(entity this) { if(this.ballcarried.teamtime && (this.ballcarried.teamtime < time)) { - bprint("The ", Team_ColoredFullName(this.team), " held the ball for too long.\n"); - DropBall(this.ballcarried, this.ballcarried.owner.origin, '0 0 0'); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD)); entity e = this.ballcarried; + DropBall(this.ballcarried, this.ballcarried.owner.origin, '0 0 0'); ResetBall(e); } else @@ -118,14 +121,16 @@ void relocate_nexball(entity this) tracebox(this.origin, BALL_MINS, BALL_MAXS, this.origin, true, this); if(trace_startsolid) { - vector o; - o = this.origin; - if(!move_out_of_solid(this)) + vector o = this.origin; + if (!move_out_of_solid(this)) { objerror(this, "could not get out of solid at all!"); - LOG_INFO("^1NOTE: this map needs FIXING. ", this.classname, " at ", vtos(o - '0 0 1')); - LOG_INFO(" needs to be moved out of solid, e.g. by '", ftos(this.origin.x - o.x)); - LOG_INFO(" ", ftos(this.origin.y - o.y)); - LOG_INFO(" ", ftos(this.origin.z - o.z), "'\n"); + } + LOG_INFOF( + "^1NOTE: this map needs FIXING. %s at %s needs to be moved out of solid, e.g. by %s", + this.classname, + vtos(o - '0 0 1'), + vtos(this.origin - o) + ); this.origin = o; } } @@ -148,6 +153,7 @@ void GiveBall(entity plyr, entity ball) { ownr.effects &= ~autocvar_g_nexball_basketball_effects_default; ownr.ballcarried = NULL; + GameRules_scoring_vip(ownr, false); if(ownr.metertime) { ownr.metertime = 0; @@ -167,8 +173,10 @@ void GiveBall(entity plyr, entity ball) ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam; ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it + ball.weaponentity_fld = weaponentity; ball.team = plyr.team; plyr.ballcarried = ball; + GameRules_scoring_vip(plyr, true); ball.nb_dropper = plyr; plyr.effects |= autocvar_g_nexball_basketball_effects_default; @@ -190,12 +198,12 @@ void GiveBall(entity plyr, entity ball) } plyr.(weaponentity).weapons = plyr.weapons; - plyr.(weaponentity).m_switchweapon = PS(plyr).m_weapon; + plyr.m_switchweapon = plyr.(weaponentity).m_weapon; plyr.weapons = WEPSET(NEXBALL); Weapon w = WEP_NEXBALL; w.wr_resetplayer(w, plyr); - PS(plyr).m_switchweapon = WEP_NEXBALL; - W_SwitchWeapon(plyr, WEP_NEXBALL); + plyr.(weaponentity).m_switchweapon = WEP_NEXBALL; + W_SwitchWeapon(plyr, WEP_NEXBALL, weaponentity); } void DropBall(entity ball, vector org, vector vel) @@ -218,7 +226,7 @@ void DropBall(entity ball, vector org, vector vel) if(ball.owner.metertime) { ball.owner.metertime = 0; - .entity weaponentity = weaponentities[0]; // TODO: find ballstealer + .entity weaponentity = ball.weaponentity_fld; ball.owner.(weaponentity).state = WS_READY; } @@ -226,13 +234,14 @@ void DropBall(entity ball, vector org, vector vel) WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT); - ball.owner.ballcarried = NULL; - ball.owner = NULL; + entity e = ball.owner; ball.owner = NULL; + e.ballcarried = NULL; + GameRules_scoring_vip(e, false); } void InitBall(entity this) { - if(gameover) return; + if(game_stopped) return; UNSET_ONGROUND(this); set_movetype(this, MOVETYPE_BOUNCE); if(this.classname == "nexball_basketball") @@ -255,7 +264,7 @@ void ResetBall(entity this) if(this.cnt < 2) // step 1 { if(time == this.teamtime) - bprint("The ", Team_ColoredFullName(this.team), " held the ball for too long.\n"); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD)); settouch(this, func_null); set_movetype(this, MOVETYPE_NOCLIP); @@ -360,7 +369,7 @@ void GoalTouch(entity this, entity toucher) float isclient, pscore, otherteam; string pname; - if(gameover) return; + if(game_stopped) return; if((this.spawnflags & GOAL_TOUCHPLAYER) && toucher.ballcarried) ball = toucher.ballcarried; else @@ -426,9 +435,9 @@ void GoalTouch(entity this, entity toucher) if(isclient) { if(pscore > 0) - PlayerScore_Add(ball.pusher, SP_NEXBALL_GOALS, pscore); + GameRules_scoring_add(ball.pusher, NEXBALL_GOALS, pscore); else if(pscore < 0) - PlayerScore_Add(ball.pusher, SP_NEXBALL_FAULTS, -pscore); + GameRules_scoring_add(ball.pusher, NEXBALL_FAULTS, -pscore); } if(ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER @@ -552,6 +561,9 @@ void SpawnBall(entity this) set_movetype(this, MOVETYPE_FLY); + if(autocvar_g_nexball_playerclip_collisions) + this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP; + if(!autocvar_g_nexball_sound_bounce) this.noise = ""; else if(this.noise == "") @@ -710,135 +722,6 @@ spawnfunc(ball_bound) spawnfunc_nexball_out(this); } -//=======================// -// Weapon code // -//=======================// - - -void W_Nexball_Think(entity this) -{ - //dprint("W_Nexball_Think\n"); - //vector new_dir = steerlib_arrive(this.enemy.origin, 2500); - vector new_dir = normalize(this.enemy.origin + '0 0 50' - this.origin); - vector old_dir = normalize(this.velocity); - float _speed = vlen(this.velocity); - vector new_vel = normalize(old_dir + (new_dir * autocvar_g_nexball_safepass_turnrate)) * _speed; - //vector new_vel = (new_dir * autocvar_g_nexball_safepass_turnrate - - this.velocity = new_vel; - - this.nextthink = time; -} - -void W_Nexball_Touch(entity this, entity toucher) -{ - entity ball, attacker; - attacker = this.owner; - //this.think = func_null; - //this.enemy = NULL; - - PROJECTILE_TOUCH(this, toucher); - if(attacker.team != toucher.team || autocvar_g_nexball_basketball_teamsteal) - if((ball = toucher.ballcarried) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (IS_PLAYER(attacker))) - { - toucher.velocity = toucher.velocity + normalize(this.velocity) * toucher.damageforcescale * autocvar_g_balance_nexball_secondary_force; - UNSET_ONGROUND(toucher); - if(!attacker.ballcarried) - { - LogNB("stole", attacker); - _sound(toucher, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM); - - if(SAME_TEAM(attacker, toucher) && time > attacker.teamkill_complain) - { - attacker.teamkill_complain = time + 5; - attacker.teamkill_soundtime = time + 0.4; - attacker.teamkill_soundsource = toucher; - } - - GiveBall(attacker, toucher.ballcarried); - } - } - delete(this); -} - -void W_Nexball_Attack(entity actor, .entity weaponentity, float t) -{ - entity ball; - float mul, mi, ma; - if(!(ball = actor.ballcarried)) - return; - - W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0); - tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, NULL); - if(trace_startsolid) - { - if(actor.metertime) - actor.metertime = 0; // Shot failed, hide the power meter - return; - } - - //Calculate multiplier - if(t < 0) - mul = 1; - else - { - mi = autocvar_g_nexball_basketball_meter_minpower; - ma = max(mi, autocvar_g_nexball_basketball_meter_maxpower); // avoid confusion - //One triangle wave period with 1 as max - mul = 2 * (t % g_nexball_meter_period) / g_nexball_meter_period; - if(mul > 1) - mul = 2 - mul; - mul = mi + (ma - mi) * mul; // range from the minimal power to the maximal power - } - - DropBall(ball, w_shotorg, W_CalculateProjectileVelocity(actor, actor.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, false)); - - - //TODO: use the speed_up cvar too ?? -} - -vector trigger_push_calculatevelocity(vector org, entity tgt, float ht); - -void W_Nexball_Attack2(entity actor, .entity weaponentity) -{ - if(actor.ballcarried.enemy) - { - entity _ball = actor.ballcarried; - W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0); - DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32)); - setthink(_ball, W_Nexball_Think); - _ball.nextthink = time; - return; - } - - if(!autocvar_g_nexball_tackling) - return; - - W_SetupShot(actor, weaponentity, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0); - entity missile = new(ballstealer); - - missile.owner = actor; - - set_movetype(missile, MOVETYPE_FLY); - PROJECTILE_MAKETRIGGER(missile); - - //setmodel(missile, "models/elaser.mdl"); // precision set below - setsize(missile, '0 0 0', '0 0 0'); - setorigin(missile, w_shotorg); - - W_SetupProjVelocity_Basic(missile, autocvar_g_balance_nexball_secondary_speed, 0); - missile.angles = vectoangles(missile.velocity); - settouch(missile, W_Nexball_Touch); - setthink(missile, SUB_Remove); - missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead? - - missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION; - missile.flags = FL_PROJECTILE; - IL_PUSH(g_projectiles, missile); - - CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true); -} - bool ball_customize(entity this, entity client) { if(!this.owner) @@ -866,56 +749,6 @@ bool ball_customize(entity this, entity client) return true; } -METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity weaponentity, int fire)) -{ - TC(BallStealer, thiswep); - if(fire & 1) - if(weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_balance_nexball_primary_refire)) - if(autocvar_g_nexball_basketball_meter) - { - if(actor.ballcarried && !actor.metertime) - actor.metertime = time; - else - weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready); - } - else - { - W_Nexball_Attack(actor, weaponentity, -1); - weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready); - } - if(fire & 2) - if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_nexball_secondary_refire)) - { - W_Nexball_Attack2(actor, weaponentity); - weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready); - } - - if(!(fire & 1) && actor.metertime && actor.ballcarried) - { - W_Nexball_Attack(actor, weaponentity, time - actor.metertime); - // DropBall or stealing will set metertime back to 0 - weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready); - } -} - -METHOD(BallStealer, wr_setup, void(BallStealer this, entity actor)) -{ - TC(BallStealer, this); - //weapon_setup(WEP_PORTO.m_id); -} - -METHOD(BallStealer, wr_checkammo1, bool(BallStealer this, entity actor)) -{ - TC(BallStealer, this); - return true; -} - -METHOD(BallStealer, wr_checkammo2, bool(BallStealer this, entity actor)) -{ - TC(BallStealer, this); - return true; -} - void nb_DropBall(entity player) { if(player.ballcarried && g_nexball) @@ -993,16 +826,20 @@ MUTATOR_HOOKFUNCTION(nb, PlayerPreThink) } else { - .entity weaponentity = weaponentities[0]; // TODO - if(player.(weaponentity).weapons) + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - player.weapons = player.(weaponentity).weapons; - Weapon w = WEP_NEXBALL; - w.wr_resetplayer(w, player); - PS(player).m_switchweapon = player.(weaponentity).m_switchweapon; - W_SwitchWeapon(player, PS(player).m_switchweapon); + .entity weaponentity = weaponentities[slot]; + + if(player.(weaponentity).weapons) + { + player.weapons = player.(weaponentity).weapons; + Weapon w = WEP_NEXBALL; + w.wr_resetplayer(w, player); + player.(weaponentity).m_switchweapon = player.m_switchweapon; + W_SwitchWeapon(player, player.(weaponentity).m_switchweapon, weaponentity); - player.(weaponentity).weapons = '0 0 0'; + player.(weaponentity).weapons = '0 0 0'; + } } } @@ -1024,8 +861,11 @@ MUTATOR_HOOKFUNCTION(nb, PlayerSpawn) entity player = M_ARGV(0, entity); player.metertime = 0; - .entity weaponentity = weaponentities[0]; - player.(weaponentity).weapons = '0 0 0'; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + player.(weaponentity).weapons = '0 0 0'; + } if (nexball_mode & NBM_BASKETBALL) player.weapons |= WEPSET(NEXBALL); @@ -1051,16 +891,18 @@ MUTATOR_HOOKFUNCTION(nb, PlayerPhysics) MUTATOR_HOOKFUNCTION(nb, ForbidThrowCurrentWeapon) { - entity player = M_ARGV(0, entity); + //entity player = M_ARGV(0, entity); + entity wepent = M_ARGV(1, entity); - return PS(player).m_weapon == WEP_NEXBALL; + return wepent.m_weapon == WEP_NEXBALL; } MUTATOR_HOOKFUNCTION(nb, ForbidDropCurrentWeapon) { - entity player = M_ARGV(0, entity); + //entity player = M_ARGV(0, entity); + int wep = M_ARGV(1, int); - return PS(player).m_weapon == WEP_MORTAR; // TODO: what is this for? + return wep == WEP_MORTAR.m_id; // TODO: what is this for? } MUTATOR_HOOKFUNCTION(nb, FilterItem) @@ -1085,7 +927,7 @@ MUTATOR_HOOKFUNCTION(nb, ItemTouch) return MUT_ITEMTOUCH_CONTINUE; } -MUTATOR_HOOKFUNCTION(nb, GetTeamCount) +MUTATOR_HOOKFUNCTION(nb, CheckAllowedTeams) { M_ARGV(1, string) = "nexball_team"; return true; @@ -1114,6 +956,7 @@ MUTATOR_HOOKFUNCTION(nb, SendWaypoint) REGISTER_MUTATOR(nb, g_nexball) { + MUTATOR_STATIC(); MUTATOR_ONADD { g_nexball_meter_period = autocvar_g_nexball_meter_period; @@ -1133,25 +976,15 @@ REGISTER_MUTATOR(nb, g_nexball) InitializeEntity(NULL, nb_delayedinit, INITPRIO_GAMETYPE); WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED; - ActivateTeamplay(); - SetLimits(autocvar_g_nexball_goallimit, autocvar_g_nexball_goalleadlimit, autocvar_timelimit_override, -1); - have_team_spawns = -1; // request team spawns + GameRules_teams(true); + GameRules_limit_score(autocvar_g_nexball_goallimit); + GameRules_limit_lead(autocvar_g_nexball_goalleadlimit); } MUTATOR_ONROLLBACK_OR_REMOVE { WEP_NEXBALL.spawnflags |= WEP_FLAG_MUTATORBLOCKED; - // we actually cannot roll back nb_delayedinit here - // BUT: we don't need to! If this gets called, adding always - // succeeds. } - - MUTATOR_ONREMOVE - { - LOG_INFO("This is a game type and it cannot be removed at runtime."); - return -1; - } - return 0; }