1 #include "sv_weapon.qh"
3 void W_Nexball_Attack(entity actor, .entity weaponentity, float t);
4 void W_Nexball_Attack2(entity actor, .entity weaponentity);
5 vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity pushed_entity);
7 METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity weaponentity, int fire))
9 TC(BallStealer, thiswep);
11 if(weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_balance_nexball_primary_refire))
12 if(autocvar_g_nexball_basketball_meter)
14 if(actor.ballcarried && !actor.metertime)
15 actor.metertime = time;
17 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
21 W_Nexball_Attack(actor, weaponentity, -1);
22 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
25 if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_nexball_secondary_refire))
27 W_Nexball_Attack2(actor, weaponentity);
28 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
31 if(!(fire & 1) && actor.metertime && actor.ballcarried)
33 W_Nexball_Attack(actor, weaponentity, time - actor.metertime);
34 // DropBall or stealing will set metertime back to 0
35 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
39 METHOD(BallStealer, wr_setup, void(BallStealer this, entity actor, .entity weaponentity))
41 TC(BallStealer, this);
42 //weapon_setup(WEP_PORTO.m_id);
45 METHOD(BallStealer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
47 TC(BallStealer, this);
50 METHOD(BallStealer, wr_checkammo1, bool(BallStealer this, entity actor, .entity weaponentity))
52 TC(BallStealer, this);
56 METHOD(BallStealer, wr_checkammo2, bool(BallStealer this, entity actor, .entity weaponentity))
58 TC(BallStealer, this);
62 void W_Nexball_Think(entity this)
64 //dprint("W_Nexball_Think\n");
65 //vector new_dir = steerlib_arrive(this.enemy.origin, 2500);
66 vector new_dir = normalize(this.enemy.origin + '0 0 50' - this.origin);
67 vector old_dir = normalize(this.velocity);
68 float _speed = vlen(this.velocity);
69 vector new_vel = normalize(old_dir + (new_dir * autocvar_g_nexball_safepass_turnrate)) * _speed;
70 //vector new_vel = (new_dir * autocvar_g_nexball_safepass_turnrate
72 this.velocity = new_vel;
74 this.nextthink = time;
77 void W_Nexball_Touch(entity this, entity toucher)
79 entity ball, attacker;
80 attacker = this.owner;
81 //this.think = func_null;
84 PROJECTILE_TOUCH(this, toucher);
85 if(attacker.team != toucher.team || autocvar_g_nexball_basketball_teamsteal)
86 if((ball = toucher.ballcarried) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (IS_PLAYER(attacker)))
88 toucher.velocity = toucher.velocity + normalize(this.velocity) * toucher.damageforcescale * autocvar_g_balance_nexball_secondary_force;
89 UNSET_ONGROUND(toucher);
90 if(!attacker.ballcarried)
92 LogNB("stole", attacker);
93 _sound(toucher, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
95 if(SAME_TEAM(attacker, toucher) && time > CS(attacker).teamkill_complain)
97 CS(attacker).teamkill_complain = time + 5;
98 CS(attacker).teamkill_soundtime = time + 0.4;
99 CS(attacker).teamkill_soundsource = toucher;
102 GiveBall(attacker, toucher.ballcarried);
108 void W_Nexball_Attack(entity actor, .entity weaponentity, float t)
112 if(!(ball = actor.ballcarried))
115 W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0, WEP_PORTO.m_id); // TODO: use ballstealer weapon here? we don't want duplicates in the scoreboard
116 tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, NULL);
120 actor.metertime = 0; // Shot failed, hide the power meter
124 //Calculate multiplier
129 mi = autocvar_g_nexball_basketball_meter_minpower;
130 ma = max(mi, autocvar_g_nexball_basketball_meter_maxpower); // avoid confusion
131 //One triangle wave period with 1 as max
132 mul = 2 * (t % g_nexball_meter_period) / g_nexball_meter_period;
135 mul = mi + (ma - mi) * mul; // range from the minimal power to the maximal power
138 DropBall(ball, w_shotorg, W_CalculateProjectileVelocity(actor, actor.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, false));
141 //TODO: use the speed_up cvar too ??
144 void W_Nexball_Attack2(entity actor, .entity weaponentity)
146 if(actor.ballcarried.enemy)
148 entity _ball = actor.ballcarried;
149 W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0, WEP_PORTO.m_id | HITTYPE_SECONDARY); // TODO: use the ball stealer weapon here? probably don't want duplicates
150 DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32, _ball));
151 setthink(_ball, W_Nexball_Think);
152 _ball.nextthink = time;
156 if(!autocvar_g_nexball_tackling)
159 W_SetupShot(actor, weaponentity, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0, WEP_PORTO.m_id);
160 entity missile = new(ballstealer);
162 missile.owner = actor;
164 set_movetype(missile, MOVETYPE_FLY);
165 PROJECTILE_MAKETRIGGER(missile);
167 //setmodel(missile, "models/elaser.mdl"); // precision set below
168 setsize(missile, '0 0 0', '0 0 0');
169 setorigin(missile, w_shotorg);
171 W_SetupProjVelocity_Basic(missile, autocvar_g_balance_nexball_secondary_speed, 0);
172 missile.angles = vectoangles(missile.velocity);
173 settouch(missile, W_Nexball_Touch);
174 setthink(missile, SUB_Remove);
175 missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead?
177 missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
178 missile.flags = FL_PROJECTILE;
179 IL_PUSH(g_projectiles, missile);
180 IL_PUSH(g_bot_dodge, missile);
182 CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);