]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_laser.qc
one step towards making the rifle the "standard sniper gun" instead of the Nex: on...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_laser.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(LASER, w_laser, 0, 1, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, 0, "laser", "laser", "Laser");
3 #else
4 #ifdef SVQC
5 void(float imp) W_SwitchWeapon;
6
7 void W_Laser_Touch (void)
8 {
9         PROJECTILE_TOUCH;
10
11         self.event_damage = SUB_Null;
12         if (self.dmg)
13                 RadiusDamage (self, self.owner, cvar("g_balance_laser_secondary_damage"), cvar("g_balance_laser_secondary_edgedamage"), cvar("g_balance_laser_secondary_radius"), world, cvar("g_balance_laser_secondary_force"), self.projectiledeathtype, other);
14         else
15                 RadiusDamage (self, self.owner, cvar("g_balance_laser_primary_damage"), cvar("g_balance_laser_primary_edgedamage"), cvar("g_balance_laser_primary_radius"), world, cvar("g_balance_laser_primary_force"), self.projectiledeathtype, other);
16
17         remove (self);
18 }
19
20 void W_Laser_Think()
21 {
22         self.movetype = MOVETYPE_FLY;
23         self.think = SUB_Remove;
24         if (self.dmg)
25                 self.nextthink = time + cvar("g_balance_laser_secondary_lifetime");
26         else
27                 self.nextthink = time + cvar("g_balance_laser_primary_lifetime");
28         CSQCProjectile(self, TRUE, PROJECTILE_LASER, TRUE);
29 }
30
31 void W_Laser_Attack (float issecondary)
32 {
33         local entity missile;
34         vector s_forward;
35         float a;
36         float nodamage;
37
38         if(issecondary == 2) // minstanex shot
39                 nodamage = g_minstagib;
40         else
41                 nodamage = FALSE;
42
43         a = cvar("g_balance_laser_primary_shotangle");
44         s_forward = v_forward * cos(a * DEG2RAD) + v_up * sin(a * DEG2RAD);
45
46         if(nodamage)
47                 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", 0);
48         else if(issecondary == 1)
49                 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", cvar("g_balance_laser_secondary_damage"));
50         else
51                 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", cvar("g_balance_laser_primary_damage"));
52         pointparticles(particleeffectnum("laser_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
53
54         missile = spawn ();
55         missile.owner = self;
56         missile.classname = "laserbolt";
57         missile.dmg = 0;
58         if(!nodamage)
59         {
60                 missile.bot_dodge = TRUE;
61                 missile.bot_dodgerating = cvar("g_balance_laser_primary_damage");
62         }
63
64         PROJECTILE_MAKETRIGGER(missile);
65         missile.projectiledeathtype = WEP_LASER;
66
67         setorigin (missile, w_shotorg);
68         setsize(missile, '0 0 0', '0 0 0');
69
70         W_SETUPPROJECTILEVELOCITY(missile, g_balance_laser_primary);
71         missile.angles = vectoangles (missile.velocity);
72         //missile.glow_color = 250; // 244, 250
73         //missile.glow_size = 120;
74         missile.touch = W_Laser_Touch;
75
76         missile.flags = FL_PROJECTILE;
77
78         missile.think = W_Laser_Think;
79         missile.nextthink = time + cvar("g_balance_laser_primary_delay");
80         if(time >= missile.nextthink)
81         {
82                 entity oldself;
83                 oldself = self;
84                 self = missile;
85                 self.think();
86                 self = oldself;
87         }
88 }
89
90 .vector hook_start, hook_end;
91 float gauntletbeam_send(entity to, float sf)
92 {
93         WriteByte(MSG_ENTITY, ENT_CLIENT_GAUNTLET);
94         sf = sf & 0x7F;
95         if(sound_allowed(MSG_BROADCAST, self.owner))
96                 sf |= 0x80;
97         WriteByte(MSG_ENTITY, sf);
98         if(sf & 1)
99         {
100                 WriteByte(MSG_ENTITY, num_for_edict(self.owner));
101         }
102         if(sf & 2)
103         {
104                 WriteCoord(MSG_ENTITY, self.hook_start_x);
105                 WriteCoord(MSG_ENTITY, self.hook_start_y);
106                 WriteCoord(MSG_ENTITY, self.hook_start_z);
107         }
108         if(sf & 4)
109         {
110                 WriteCoord(MSG_ENTITY, self.hook_end_x);
111                 WriteCoord(MSG_ENTITY, self.hook_end_y);
112                 WriteCoord(MSG_ENTITY, self.hook_end_z);
113         }
114         return TRUE;
115 }
116 .entity gauntletbeam;
117 .float prevgauntletfire;
118 void gauntletbeam_think()
119 {
120         float damage, myforce, myradius;
121         damage = cvar("g_balance_laser_secondary_damage");
122         myforce = cvar("g_balance_laser_secondary_force");
123         myradius = cvar("g_balance_laser_secondary_radius");
124
125         self.owner.prevgauntletfire = time;
126         if (self.owner.weaponentity.state != WS_INUSE || self != self.owner.gauntletbeam || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK2)
127         {
128                 remove(self);
129                 return;
130         }
131
132         self.nextthink = time;
133
134         makevectors(self.owner.v_angle);
135
136         float dt;
137         dt = frametime;
138
139         W_SetupShot_Range(self.owner, TRUE, 0, "", damage * dt, myradius);
140         WarpZone_traceline_antilag(self.owner, w_shotorg, w_shotend, MOVE_NORMAL, self.owner, ANTILAG_LATENCY(self.owner));
141
142         // apply the damage
143         if(trace_ent)
144         {
145                 vector force;
146                 force = w_shotdir * myforce;
147                 Damage (trace_ent, self.owner, self.owner, damage * dt, WEP_LASER | HITTYPE_SECONDARY, trace_endpos, force * dt);
148                 Damage_RecordDamage(self.owner, WEP_LASER | HITTYPE_SECONDARY, damage * dt);
149         }
150
151         // draw effect
152         if(w_shotorg != self.hook_start)
153         {
154                 self.SendFlags |= 2;
155                 self.hook_start = w_shotorg;
156         }
157         if(w_shotend != self.hook_end)
158         {
159                 self.SendFlags |= 4;
160                 self.hook_end = w_shotend;
161         }
162 }
163
164 // experimental gauntlet
165 void W_Laser_Attack2 ()
166 {
167         // only play fire sound if 0.5 sec has passed since player let go the fire button
168         if(time - self.prevgauntletfire > 0.5)
169         {
170                 sound (self, CHAN_WEAPON, "weapons/gauntlet_fire.wav", VOL_BASE, ATTN_NORM);
171         }
172
173         entity beam, oldself;
174
175         self.gauntletbeam = beam = spawn();
176         beam.solid = SOLID_NOT;
177         beam.think = gauntletbeam_think;
178         beam.owner = self;
179         beam.movetype = MOVETYPE_NONE;
180         beam.shot_spread = 0;
181         beam.bot_dodge = TRUE;
182         beam.bot_dodgerating = cvar("g_balance_laser_primary_damage");
183         Net_LinkEntity(beam, FALSE, 0, gauntletbeam_send);
184
185         oldself = self;
186         self = beam;
187         self.think();
188         self = oldself;
189 }
190
191 void LaserInit()
192 {
193         weapon_action(WEP_LASER, WR_PRECACHE);
194         gauntlet_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 1);
195         gauntlet_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 2);
196         gauntlet_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 3);
197         gauntlet_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 4);
198 }
199
200 void spawnfunc_weapon_laser (void)
201 {
202         weapon_defaultspawnfunc(WEP_LASER);
203 }
204
205 float w_laser(float req)
206 {
207         local float r1;
208         local float r2;
209         if (req == WR_AIM)
210         {
211                 if(cvar("g_balance_laser_secondary"))
212                 {
213                         r1 = cvar("g_balance_laser_primary_damage");
214                         r2 = cvar("g_balance_laser_secondary_damage");
215                         if (random() * (r2 + r1) > r1)
216                                 self.BUTTON_ATCK2 = bot_aim(cvar("g_balance_laser_secondary_speed"), 0, cvar("g_balance_laser_secondary_lifetime"), FALSE);
217                         else
218                                 self.BUTTON_ATCK = bot_aim(cvar("g_balance_laser_primary_speed"), 0, cvar("g_balance_laser_primary_lifetime"), FALSE);
219                 }
220                 else
221                         self.BUTTON_ATCK = bot_aim(cvar("g_balance_laser_primary_speed"), 0, cvar("g_balance_laser_primary_lifetime"), FALSE);
222         }
223         else if (req == WR_THINK)
224         {
225                 if (self.BUTTON_ATCK)
226                 if (weapon_prepareattack(0, cvar("g_balance_laser_primary_refire")))
227                 {
228                         W_Laser_Attack(1);
229                         weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_laser_primary_animtime"), w_ready);
230                 }
231                 if (self.BUTTON_ATCK2)
232                 {
233                         if(cvar("g_balance_laser_secondary"))
234                         {
235                                 if (weapon_prepareattack(0, 0))
236                                 {
237                                         W_Laser_Attack2();
238                                         weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_laser_secondary_animtime"), w_ready);
239                                 }
240                         }
241                         else
242                         {
243                                 if(self.switchweapon == WEP_LASER) // don't do this if already switching
244                                         W_SwitchWeapon (self.cnt);
245                         }
246                 }
247         }
248         else if (req == WR_PRECACHE)
249         {
250                 precache_model ("models/weapons/g_laser.md3");
251                 precache_model ("models/weapons/v_laser.md3");
252                 precache_model ("models/weapons/h_laser.iqm");
253                 precache_sound ("weapons/lasergun_fire.wav");
254                 precache_sound ("weapons/gauntlet_fire.wav");
255         }
256         else if (req == WR_SETUP)
257                 weapon_setup(WEP_LASER);
258         else if (req == WR_CHECKAMMO1)
259                 return TRUE;
260         else if (req == WR_CHECKAMMO2)
261                 return TRUE;
262         return TRUE;
263 };
264 #endif
265 #ifdef CSQC
266 float w_laser(float req)
267 {
268         if(req == WR_IMPACTEFFECT)
269         {
270                 vector org2;
271                 org2 = w_org + w_backoff * 6;
272                 pointparticles(particleeffectnum("laser_impact"), org2, w_backoff * 1000, 1);
273                 if(!w_issilent)
274                         sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
275         }
276         else if(req == WR_PRECACHE)
277         {
278                 precache_sound("weapons/laserimpact.wav");
279         }
280         else if (req == WR_SUICIDEMESSAGE)
281                 w_deathtypestring = "%s lasered themself to hell";
282         else if (req == WR_KILLMESSAGE)
283         {
284                 if(w_deathtype & HITTYPE_SECONDARY)
285                         w_deathtypestring = "%s was cut in half by %s's gauntlet"; // unchecked: SPLASH
286                 else
287                         w_deathtypestring = "%s was lasered to death by %s"; // unchecked: SPLASH
288         }
289         return TRUE;
290 }
291 #endif
292 #endif