2 REGISTER_WEAPON(LASER, w_laser, 0, 1, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, 0, "laser", "laser", _("Laser"))
5 void(float imp) W_SwitchWeapon;
8 void W_Laser_Touch (void)
12 self.event_damage = SUB_Null;
14 RadiusDamage (self, self.realowner, autocvar_g_balance_laser_secondary_damage, autocvar_g_balance_laser_secondary_edgedamage, autocvar_g_balance_laser_secondary_radius, world, autocvar_g_balance_laser_secondary_force, self.projectiledeathtype, other);
16 RadiusDamage (self, self.realowner, autocvar_g_balance_laser_primary_damage, autocvar_g_balance_laser_primary_edgedamage, autocvar_g_balance_laser_primary_radius, world, autocvar_g_balance_laser_primary_force, self.projectiledeathtype, other);
23 self.movetype = MOVETYPE_FLY;
24 self.think = SUB_Remove;
26 self.nextthink = time + autocvar_g_balance_laser_secondary_lifetime;
28 self.nextthink = time + autocvar_g_balance_laser_primary_lifetime;
29 CSQCProjectile(self, TRUE, PROJECTILE_LASER, TRUE);
32 void W_Laser_Shockwave (void)
35 float final_damage, final_spread;
37 vector nearest, attack_endpos, angle_to_head, angle_to_attack, final_force;
39 // set up the shot direction
40 vector wanted_shot_direction = (v_forward * cos(autocvar_g_balance_laser_primary_shotangle * DEG2RAD) + v_up * sin(autocvar_g_balance_laser_primary_shotangle * DEG2RAD));
41 W_SetupShot_Dir(self, wanted_shot_direction, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_balance_laser_primary_damage);
42 vector targpos = (w_shotorg + (w_shotdir * autocvar_g_balance_laser_primary_jumpradius));
44 // trace to see if this is a self jump
45 WarpZone_TraceLine(w_shotorg, targpos, FALSE, self);
46 //te_lightning2(world, targpos, w_shotorg);
48 if(trace_fraction < 1) // Yes, it is a close range jump
50 RadiusDamageForSource(self, trace_endpos, '0 0 0', self, autocvar_g_balance_laser_primary_damage, autocvar_g_balance_laser_primary_edgedamage, autocvar_g_balance_laser_primary_jumpradius, world, TRUE, autocvar_g_balance_laser_primary_force, WEP_LASER, world);
51 pointparticles(particleeffectnum("laser_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
53 else // No, it's a mid range attack
55 // find out what i'm pointing at
56 targpos = (w_shotorg + (w_shotdir * autocvar_g_balance_laser_primary_radius));
57 WarpZone_TraceLine(w_shotorg, targpos, MOVE_WORLDONLY, self);
59 te_lightning2(world, trace_endpos, w_shotorg);
61 attack_endpos = trace_endpos;
62 //total_attack_range = vlen(w_shotorg - trace_endpos);
64 // now figure out if I hit anything...
65 head = WarpZone_FindRadius(attack_endpos, vlen(w_shotorg - trace_endpos) + MAX_DAMAGEEXTRARADIUS, FALSE);
70 if((head != self) && (head.takedamage))
72 // is it in range of the attack?
73 nearest = WarpZoneLib_NearestPointOnBox(head.origin + head.mins, head.origin + head.maxs, w_shotorg);
74 if(vlen(w_shotorg - nearest) <= autocvar_g_balance_laser_primary_radius)
76 // is it within the limit of the spread?
77 nearest = head.WarpZone_findradius_nearest;
78 angle_to_head = normalize(nearest - w_shotorg);
79 angle_to_attack = w_shotdir;
80 final_spread = vlen(angle_to_head - angle_to_attack);
81 if(final_spread <= autocvar_g_balance_laser_primary_spread)
83 // is it visible to the weapon?
84 //WarpZone_TraceLine(w_shotorg, nearest, MOVE_WORLDONLY, self);
85 //if(trace_fraction == 1)
87 // finally lets do some damage bitches!
88 if(autocvar_g_balance_laser_primary_spread)
89 final_damage = (final_spread / autocvar_g_balance_laser_primary_spread);
93 final_force = (normalize(nearest - w_shotorg) * autocvar_g_balance_laser_primary_force);
94 final_damage = (autocvar_g_balance_laser_primary_damage * final_damage + autocvar_g_balance_laser_primary_edgedamage * (1 - final_damage));
96 Damage(head, self, self, final_damage, WEP_LASER, w_shotorg, final_force);
98 print(strcat(vtos(angle_to_head), " - ", vtos(angle_to_attack), ": ", ftos(vlen(angle_to_head - angle_to_attack)), ".\n"));
99 te_lightning2(world, nearest, w_shotorg);
107 pointparticles(particleeffectnum("laser_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
111 void W_Laser_Attack (float issecondary)
118 if(issecondary == 2) // minstanex shot
119 nodamage = g_minstagib;
123 a = autocvar_g_balance_laser_primary_shotangle;
124 s_forward = v_forward * cos(a * DEG2RAD) + v_up * sin(a * DEG2RAD);
127 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, 0);
128 else if(issecondary == 1)
129 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_balance_laser_secondary_damage);
131 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_balance_laser_primary_damage);
132 pointparticles(particleeffectnum("laser_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
135 missile.owner = missile.realowner = self;
136 missile.classname = "laserbolt";
140 missile.bot_dodge = TRUE;
141 missile.bot_dodgerating = autocvar_g_balance_laser_primary_damage;
144 PROJECTILE_MAKETRIGGER(missile);
145 missile.projectiledeathtype = WEP_LASER;
147 setorigin (missile, w_shotorg);
148 setsize(missile, '0 0 0', '0 0 0');
150 W_SETUPPROJECTILEVELOCITY(missile, g_balance_laser_primary);
151 missile.angles = vectoangles (missile.velocity);
152 //missile.glow_color = 250; // 244, 250
153 //missile.glow_size = 120;
154 missile.touch = W_Laser_Touch;
156 missile.flags = FL_PROJECTILE;
158 missile.think = W_Laser_Think;
159 missile.nextthink = time + autocvar_g_balance_laser_primary_delay;
161 other = missile; MUTATOR_CALLHOOK(EditProjectile);
163 if(time >= missile.nextthink)
173 .vector hook_start, hook_end;
174 float gauntletbeam_send(entity to, float sf)
176 WriteByte(MSG_ENTITY, ENT_CLIENT_GAUNTLET);
178 if(sound_allowed(MSG_BROADCAST, self.realowner))
180 WriteByte(MSG_ENTITY, sf);
183 WriteByte(MSG_ENTITY, num_for_edict(self.realowner));
187 WriteCoord(MSG_ENTITY, self.hook_start_x);
188 WriteCoord(MSG_ENTITY, self.hook_start_y);
189 WriteCoord(MSG_ENTITY, self.hook_start_z);
193 WriteCoord(MSG_ENTITY, self.hook_end_x);
194 WriteCoord(MSG_ENTITY, self.hook_end_y);
195 WriteCoord(MSG_ENTITY, self.hook_end_z);
199 .entity gauntletbeam;
200 .float prevgauntletfire;
201 entity lgbeam_owner_ent;
202 void gauntletbeam_think()
204 float damage, myforce, myradius;
205 damage = autocvar_g_balance_laser_secondary_damage;
206 myforce = autocvar_g_balance_laser_secondary_force;
207 myradius = autocvar_g_balance_laser_secondary_radius;
209 self.realowner.prevgauntletfire = time;
210 if (self.realowner.weaponentity.state != WS_INUSE || self != self.realowner.gauntletbeam || self.realowner.deadflag != DEAD_NO || !self.realowner.BUTTON_ATCK2)
216 self.nextthink = time;
218 makevectors(self.realowner.v_angle);
223 W_SetupShot_Range(self.realowner, TRUE, 0, "", 0, damage * dt, myradius);
224 if(!lgbeam_owner_ent)
226 lgbeam_owner_ent = spawn();
227 lgbeam_owner_ent.classname = "lgbeam_owner_ent";
229 WarpZone_traceline_antilag(lgbeam_owner_ent, w_shotorg, w_shotend, MOVE_NORMAL, lgbeam_owner_ent, ANTILAG_LATENCY(self.owner));
235 force = w_shotdir * myforce;
236 if(accuracy_isgooddamage(self.owner, trace_ent))
237 accuracy_add(self.owner, WEP_LASER, 0, damage * dt);
238 Damage (trace_ent, self.owner, self.owner, damage * dt, WEP_LASER | HITTYPE_SECONDARY, trace_endpos, force * dt);
242 if(w_shotorg != self.hook_start)
245 self.hook_start = w_shotorg;
247 if(w_shotend != self.hook_end)
250 self.hook_end = w_shotend;
254 // experimental gauntlet
255 void W_Laser_Attack2 ()
257 // only play fire sound if 0.5 sec has passed since player let go the fire button
258 if(time - self.prevgauntletfire > 0.5)
260 sound (self, CH_WEAPON_A, "weapons/gauntlet_fire.wav", VOL_BASE, ATTN_NORM);
263 entity beam, oldself;
265 self.gauntletbeam = beam = spawn();
266 beam.solid = SOLID_NOT;
267 beam.think = gauntletbeam_think;
269 beam.movetype = MOVETYPE_NONE;
270 beam.shot_spread = 0;
271 beam.bot_dodge = TRUE;
272 beam.bot_dodgerating = autocvar_g_balance_laser_primary_damage;
273 Net_LinkEntity(beam, FALSE, 0, gauntletbeam_send);
283 weapon_action(WEP_LASER, WR_PRECACHE);
284 gauntlet_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 1);
285 gauntlet_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 2);
286 gauntlet_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 3);
287 gauntlet_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 4);
290 void spawnfunc_weapon_laser (void)
292 weapon_defaultspawnfunc(WEP_LASER);
295 float w_laser(float req)
301 if(autocvar_g_balance_laser_secondary)
303 r1 = autocvar_g_balance_laser_primary_damage;
304 r2 = autocvar_g_balance_laser_secondary_damage;
305 if (random() * (r2 + r1) > r1)
306 self.BUTTON_ATCK2 = bot_aim(autocvar_g_balance_laser_secondary_speed, 0, autocvar_g_balance_laser_secondary_lifetime, FALSE);
308 self.BUTTON_ATCK = bot_aim(autocvar_g_balance_laser_primary_speed, 0, autocvar_g_balance_laser_primary_lifetime, FALSE);
311 self.BUTTON_ATCK = bot_aim(autocvar_g_balance_laser_primary_speed, 0, autocvar_g_balance_laser_primary_lifetime, FALSE);
313 else if (req == WR_THINK)
315 if(autocvar_g_balance_laser_reload_ammo && self.clip_load < 1) // forced reload
316 weapon_action(self.weapon, WR_RELOAD);
317 else if (self.BUTTON_ATCK)
319 if (weapon_prepareattack(0, autocvar_g_balance_laser_primary_refire))
321 W_DecreaseAmmo(ammo_none, 1, TRUE);
324 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_laser_primary_animtime, w_ready);
327 else if (self.BUTTON_ATCK2)
329 if(autocvar_g_balance_laser_secondary)
331 W_DecreaseAmmo(ammo_none, 1, TRUE);
333 if (weapon_prepareattack(0, 0))
336 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_laser_secondary_animtime, w_ready);
341 if(self.switchweapon == WEP_LASER) // don't do this if already switching
346 else if (req == WR_PRECACHE)
348 precache_model ("models/weapons/g_laser.md3");
349 precache_model ("models/weapons/v_laser.md3");
350 precache_model ("models/weapons/h_laser.iqm");
351 precache_sound ("weapons/lasergun_fire.wav");
352 precache_sound ("weapons/gauntlet_fire.wav");
353 //precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound somewhere else
355 else if (req == WR_SETUP)
357 weapon_setup(WEP_LASER);
358 self.current_ammo = ammo_none;
360 else if (req == WR_CHECKAMMO1)
364 else if (req == WR_CHECKAMMO2)
368 else if (req == WR_RELOAD)
370 W_Reload(0, autocvar_g_balance_laser_reload_ammo, autocvar_g_balance_laser_reload_time, "weapons/reload.wav");
376 float w_laser(float req)
378 if(req == WR_IMPACTEFFECT)
381 org2 = w_org + w_backoff * 6;
382 pointparticles(particleeffectnum("laser_impact"), org2, w_backoff * 1000, 1);
384 sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
386 else if(req == WR_PRECACHE)
388 precache_sound("weapons/laserimpact.wav");
390 else if (req == WR_SUICIDEMESSAGE)
391 w_deathtypestring = _("%s lasered themself to hell");
392 else if (req == WR_KILLMESSAGE)
394 if(w_deathtype & HITTYPE_SECONDARY)
395 w_deathtypestring = _("%s was cut in half by %s's gauntlet"); // unchecked: SPLASH
397 w_deathtypestring = _("%s was lasered to death by %s"); // unchecked: SPLASH