]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_lightning.qc
Merge remote-tracking branch 'origin/master' into samual/lightning_gun
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_lightning.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(LIGHTNING, w_lightning, IT_CELLS, 5, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "lightning", "lightning", _("Lightning"));
3 #else
4 #ifdef SVQC
5
6 // Declarations ========================= 
7 .vector hook_start, hook_end; // used for beam
8 .entity lightning_beam; // used for beam
9 .float BUTTON_ATCK_prev; // for better animation control
10 .float lg_fire_prev; // for better animation control
11
12 // Lightning functions ========================= 
13 float W_Lightning_Beam_Send(entity to, float sf)
14 {
15         WriteByte(MSG_ENTITY, ENT_CLIENT_LIGHTNING_BEAM);
16         sf = sf & 0x7F;
17         if(sound_allowed(MSG_BROADCAST, self.owner))
18                 sf |= 0x80;
19         WriteByte(MSG_ENTITY, sf);
20         if(sf & 1)
21         {
22                 WriteByte(MSG_ENTITY, num_for_edict(self.owner));
23                 WriteCoord(MSG_ENTITY, autocvar_g_balance_lightning_primary_range);
24         }
25         if(sf & 2)
26         {
27                 WriteCoord(MSG_ENTITY, self.hook_start_x);
28                 WriteCoord(MSG_ENTITY, self.hook_start_y);
29                 WriteCoord(MSG_ENTITY, self.hook_start_z);
30         }
31         if(sf & 4)
32         {
33                 WriteCoord(MSG_ENTITY, self.hook_end_x);
34                 WriteCoord(MSG_ENTITY, self.hook_end_y);
35                 WriteCoord(MSG_ENTITY, self.hook_end_z);
36         }
37         return TRUE;
38 }
39
40 void W_Lightning_Beam_Think()
41 {
42         self.owner.lg_fire_prev = time;
43         if (self != self.owner.lightning_beam)
44         {
45                 remove(self);
46                 return;
47         }
48         if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK || self.owner.freezetag_frozen)
49         {
50                 if(self == self.owner.lightning_beam)
51                         self.owner.lightning_beam = world;
52                 remove(self);
53                 return;
54         }
55
56         self.nextthink = time;
57
58         makevectors(self.owner.v_angle);
59
60         float dt, f;
61         dt = frametime;
62         if not(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)
63         {
64                 if(autocvar_g_balance_lightning_primary_ammo)
65                 {
66                         dt = min(dt, self.owner.ammo_cells / autocvar_g_balance_lightning_primary_ammo);
67                         self.owner.ammo_cells = max(0, self.owner.ammo_cells - autocvar_g_balance_lightning_primary_ammo * frametime);
68                 }
69         }
70
71         W_SetupShot_Range(self.owner, TRUE, 0, "", 0, autocvar_g_balance_lightning_primary_damage * dt, autocvar_g_balance_lightning_primary_range);
72         WarpZone_traceline_antilag(self.owner, w_shotorg, w_shotend, MOVE_NORMAL, self.owner, ANTILAG_LATENCY(self.owner));
73
74         // apply the damage
75         if(trace_ent)
76         {
77                 vector force;
78                 force = w_shotdir * autocvar_g_balance_lightning_primary_force;
79
80                 f = ExponentialFalloff(autocvar_g_balance_lightning_primary_falloff_mindist, autocvar_g_balance_lightning_primary_falloff_maxdist, autocvar_g_balance_lightning_primary_falloff_halflifedist, vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos) - w_shotorg));
81
82                 if(accuracy_isgooddamage(self.owner, trace_ent))
83                         accuracy_add(self.owner, WEP_LIGHTNING, 0, autocvar_g_balance_lightning_primary_damage * dt * f);
84                 Damage (trace_ent, self.owner, self.owner, autocvar_g_balance_lightning_primary_damage * dt * f, WEP_LIGHTNING, trace_endpos, force * dt);
85         }
86
87         // draw effect
88         if(w_shotorg != self.hook_start)
89         {
90                 self.SendFlags |= 2;
91                 self.hook_start = w_shotorg;
92         }
93         if(w_shotend != self.hook_end)
94         {
95                 self.SendFlags |= 4;
96                 self.hook_end = w_shotend;
97         }
98 }
99
100 // Attack functions ========================= 
101 void W_Lightning_Attack1 (void)
102 {
103         // only play fire sound if 0.5 sec has passed since player let go the fire button
104         if(time - self.lg_fire_prev > 0.5)
105                 sound (self, CHAN_WEAPON, "weapons/lgbeam_fire.wav", VOL_BASE, ATTN_NORM);
106
107         entity beam, oldself;
108
109         self.lightning_beam = beam = spawn();
110         beam.classname = "W_Lightning_Beam";
111         beam.solid = SOLID_NOT;
112         beam.think = W_Lightning_Beam_Think;
113         beam.owner = self;
114         beam.movetype = MOVETYPE_NONE;
115         beam.shot_spread = 1;
116         beam.bot_dodge = TRUE;
117         beam.bot_dodgerating = autocvar_g_balance_lightning_primary_damage;
118         Net_LinkEntity(beam, FALSE, 0, W_Lightning_Beam_Send);
119
120         oldself = self;
121         self = beam;
122         self.think();
123         self = oldself;
124 }
125
126 float w_lightning(float req)
127 {
128         if (req == WR_AIM)
129         {
130                 self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
131                 /*
132                 self.BUTTON_ATCK=FALSE;
133                 self.BUTTON_ATCK2=FALSE;
134                 if(vlen(self.origin-self.enemy.origin) > 1000)
135                         self.bot_aim_whichfiretype = 0;
136                 if(self.bot_aim_whichfiretype == 0)
137                 {
138                         float shoot;
139
140                         if(autocvar_g_balance_lightning_primary_speed)
141                                 shoot = bot_aim(autocvar_g_balance_lightning_primary_speed, 0, autocvar_g_balance_lightning_primary_lifetime, FALSE);
142                         else
143                                 shoot = bot_aim(1000000, 0, 0.001, FALSE);
144
145                         if(shoot)
146                         {
147                                 self.BUTTON_ATCK = TRUE;
148                                 if(random() < 0.01) self.bot_aim_whichfiretype = 1;
149                         }
150                 }
151                 else // todo
152                 {
153                         //if(bot_aim(autocvar_g_balance_lightning_secondary_speed, autocvar_g_balance_grenadelauncher_secondary_speed_up, autocvar_g_balance_lightning_secondary_lifetime, TRUE))
154                         //{
155                         //      self.BUTTON_ATCK2 = TRUE;
156                         //      if(random() < 0.03) self.bot_aim_whichfiretype = 0;
157                         //}
158                 }
159                 */
160         }
161         else if (req == WR_THINK)
162         {
163                 if (self.BUTTON_ATCK)
164                 {
165                         if(self.BUTTON_ATCK_prev)
166                                 if(self.animstate_startframe == self.anim_shoot_x && self.animstate_numframes == self.anim_shoot_y)
167                                         weapon_thinkf(WFRAME_DONTCHANGE, autocvar_g_balance_lightning_primary_animtime, w_ready);
168                                 else
169                                         weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_lightning_primary_animtime, w_ready);
170                         
171                         if (weapon_prepareattack(0, 0))
172                         {
173                                 if ((!self.lightning_beam) || wasfreed(self.lightning_beam))
174                                         W_Lightning_Attack1();
175                                 
176                                 if(!self.BUTTON_ATCK_prev)
177                                 {
178                                         weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_lightning_primary_animtime, w_ready);
179                                         self.BUTTON_ATCK_prev = 1;
180                                 }
181                         }
182                 } 
183                 else // todo
184                 {
185                         if (self.BUTTON_ATCK_prev != 0)
186                         {
187                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_lightning_primary_animtime, w_ready);
188                                 ATTACK_FINISHED(self) = time + autocvar_g_balance_lightning_primary_refire * W_WeaponRateFactor();
189                         }
190                         self.BUTTON_ATCK_prev = 0;
191                 }
192
193                 //if (self.BUTTON_ATCK2)
194                         //if (weapon_prepareattack(1, autocvar_g_balance_lightning_secondary_refire))
195                         //{
196                         //      W_Lightning_Attack2();
197                         //      self.lightning_count = autocvar_g_balance_lightning_secondary_count;
198                         //      weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_lightning_secondary_animtime, w_lightning_checkattack);
199                         //      self.lightning_secondarytime = time + autocvar_g_balance_lightning_secondary_refire2 * W_WeaponRateFactor();
200                         //}
201         }
202         else if (req == WR_PRECACHE)
203         {
204                 precache_model ("models/weapons/g_lightning.md3");
205                 precache_model ("models/weapons/v_lightning.md3");
206                 precache_model ("models/weapons/h_lightning.iqm");
207                 //precache_sound ("weapons/lightning_bounce.wav");
208                 precache_sound ("weapons/lightning_fire.wav");
209                 precache_sound ("weapons/lightning_fire2.wav");
210                 precache_sound ("weapons/lightning_impact.wav");
211                 //precache_sound ("weapons/lightning_impact_combo.wav");
212                 //precache_sound ("weapons/W_Lightning_Beam_fire.wav");
213         }
214         else if (req == WR_SETUP)
215                 weapon_setup(WEP_LIGHTNING);
216         else if (req == WR_CHECKAMMO1)
217         {
218                 return !autocvar_g_balance_lightning_primary_ammo || (self.ammo_cells > 0);
219         }
220         else if (req == WR_CHECKAMMO2)
221                 return self.ammo_cells >= autocvar_g_balance_lightning_secondary_ammo;
222         else if (req == WR_RESETPLAYER)
223         {
224                 //self.lightning_secondarytime = time;
225         }
226         return TRUE;
227 };
228
229 void LightningInit()
230 {
231         weapon_action(WEP_LIGHTNING, WR_PRECACHE);
232         lightning_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LIGHTNING), FALSE, FALSE, 1);
233         lightning_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LIGHTNING), FALSE, FALSE, 2);
234         lightning_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LIGHTNING), FALSE, FALSE, 3);
235         lightning_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LIGHTNING), FALSE, FALSE, 4);
236 }
237
238 void spawnfunc_weapon_lightning (void) // should this really be here?
239 {
240         weapon_defaultspawnfunc(WEP_LIGHTNING);
241 }
242 #endif
243 #ifdef CSQC
244 float w_lightning(float req)
245 {
246         if(req == WR_IMPACTEFFECT)
247         {
248                 vector org2;
249                 org2 = w_org + w_backoff * 6;
250                 
251                 if(w_deathtype & HITTYPE_SECONDARY)
252                 {
253                         pointparticles(particleeffectnum("lightning_ballexplode"), org2, '0 0 0', 1);
254                         if(!w_issilent)
255                                 sound(self, CHAN_PROJECTILE, "weapons/lightning_impact.wav", VOL_BASE, ATTN_NORM);
256                 }
257                 else
258                 {
259                         pointparticles(particleeffectnum("lightning_impact"), org2, '0 0 0', 1);
260                         if(!w_issilent)
261                                 sound(self, CHAN_PROJECTILE, "weapons/lightning_impact.wav", VOL_BASE, ATTN_NORM);
262                 }
263         }
264         else if(req == WR_PRECACHE)
265         {
266                 precache_sound("weapons/lightning_impact.wav");
267                 precache_sound("weapons/lightning_impact_combo.wav");
268         }
269         else if (req == WR_SUICIDEMESSAGE)
270         {
271                 if(w_deathtype & HITTYPE_SECONDARY)
272                         w_deathtypestring = _("%s could not remember where they put plasma");
273                 else
274                         w_deathtypestring = _("%s played with plasma");
275         }
276         else if (req == WR_KILLMESSAGE)
277         {
278                 if(w_deathtype & HITTYPE_SECONDARY)
279                 {
280                         if(w_deathtype & HITTYPE_SPLASH) // unchecked: BOUNCE
281                                 w_deathtypestring = _("%s just noticed %s's blue ball");
282                         else // unchecked: BOUNCE
283                                 w_deathtypestring = _("%s got in touch with %s's blue ball");
284                 }
285                 else
286                 {
287                         if(w_deathtype & HITTYPE_BOUNCE) // combo
288                                 w_deathtypestring = _("%s felt the electrifying air of %s's combo");
289                         else if(w_deathtype & HITTYPE_SPLASH)
290                                 w_deathtypestring = _("%s got too close to %s's blue beam");
291                         else
292                                 w_deathtypestring = _("%s was blasted by %s's blue beam");
293                 }
294         }
295         return TRUE;
296 }
297 #endif
298 #endif