]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_laser.qc
mostly working code to use csqc entities for hook, electro, gauntlet (currently doesn...
[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         if (issecondary == 1)
44                 a = cvar("g_balance_laser_secondary_shotangle");
45         else
46                 a = cvar("g_balance_laser_primary_shotangle");
47         s_forward = v_forward * cos(a * DEG2RAD) + v_up * sin(a * DEG2RAD);
48
49         if(nodamage)
50                 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", 0);
51         else if(issecondary == 1)
52                 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", cvar("g_balance_laser_secondary_damage"));
53         else
54                 W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", cvar("g_balance_laser_primary_damage"));
55         pointparticles(particleeffectnum("laser_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
56
57         missile = spawn ();
58         missile.owner = self;
59         missile.classname = "laserbolt";
60         missile.dmg = (issecondary == 1);
61         if(!nodamage)
62         {
63                 missile.bot_dodge = TRUE;
64                 if (issecondary == 1)
65                         missile.bot_dodgerating = cvar("g_balance_laser_secondary_damage");
66                 else
67                         missile.bot_dodgerating = cvar("g_balance_laser_primary_damage");
68         }
69
70         PROJECTILE_MAKETRIGGER(missile);
71         missile.projectiledeathtype = WEP_LASER;
72         if(issecondary == 1)
73                 missile.projectiledeathtype |= HITTYPE_SECONDARY;
74
75         setorigin (missile, w_shotorg);
76         setsize(missile, '0 0 0', '0 0 0');
77
78         if (issecondary == 1)
79                 W_SETUPPROJECTILEVELOCITY(missile, g_balance_laser_secondary);
80         else
81                 W_SETUPPROJECTILEVELOCITY(missile, g_balance_laser_primary);
82         missile.angles = vectoangles (missile.velocity);
83         //missile.glow_color = 250; // 244, 250
84         //missile.glow_size = 120;
85         missile.touch = W_Laser_Touch;
86
87         missile.flags = FL_PROJECTILE;
88
89         missile.think = W_Laser_Think;
90         if (issecondary == 1)
91                 missile.nextthink = time + cvar("g_balance_laser_secondary_delay");
92         else
93                 missile.nextthink = time + cvar("g_balance_laser_primary_delay");
94         if(time >= missile.nextthink)
95         {
96                 entity oldself;
97                 oldself = self;
98                 self = missile;
99                 self.think();
100                 self = oldself;
101         }
102 }
103
104 .vector hook_start, hook_end;
105 float gauntletbeam_send(entity to, float sf)
106 {
107         WriteByte(MSG_ENTITY, ENT_CLIENT_GAUNTLET);
108         sf = sf & 0x7F;
109         if(sound_allowed(MSG_BROADCAST, self.owner))
110                 sf |= 0x80;
111         WriteByte(MSG_ENTITY, sf);
112         if(sf & 1)
113         {
114                 WriteByte(MSG_ENTITY, num_for_edict(self.owner));
115         }
116         if(sf & 2)
117         {
118                 WriteCoord(MSG_ENTITY, self.hook_start_x);
119                 WriteCoord(MSG_ENTITY, self.hook_start_y);
120                 WriteCoord(MSG_ENTITY, self.hook_start_z);
121         }
122         if(sf & 4)
123         {
124                 WriteCoord(MSG_ENTITY, self.hook_end_x);
125                 WriteCoord(MSG_ENTITY, self.hook_end_y);
126                 WriteCoord(MSG_ENTITY, self.hook_end_z);
127         }
128         return TRUE;
129 }
130 .entity gauntletbeam;
131 .float prevgauntletfire;
132 void gauntletbeam_think()
133 {
134         float damage, myforce, myradius;
135         if(self.cnt)
136         {
137                 damage = cvar("g_balance_laser_secondary_damage");
138                 myforce = cvar("g_balance_laser_secondary_force");
139                 myradius = cvar("g_balance_laser_secondary_radius");
140         }
141         else
142         {
143                 damage = cvar("g_balance_laser_primary_damage");
144                 myforce = cvar("g_balance_laser_primary_force");
145                 myradius = cvar("g_balance_laser_primary_radius");
146         }
147
148         self.owner.prevgauntletfire = time;
149         if (self.owner.weaponentity.state != WS_INUSE || self != self.owner.gauntletbeam || self.owner.deadflag != DEAD_NO || (!self.owner.BUTTON_ATCK2 && self.cnt) || (!self.owner.BUTTON_ATCK && !self.cnt))
150         {
151                 remove(self);
152                 return;
153         }
154
155         self.nextthink = time;
156
157         makevectors(self.owner.v_angle);
158         vector angle;
159         angle = v_forward;
160
161         WarpZone_traceline_antilag(self.owner, self.owner.origin + self.owner.view_ofs, self.owner.origin + self.owner.view_ofs + angle * myradius, FALSE, self.owner, ANTILAG_LATENCY(self.owner));
162
163         // apply the damage
164         if(trace_fraction < 1)
165         {
166                 vector force;
167                 force = angle * myforce;
168                 Damage (trace_ent, self.owner, self.owner, damage * frametime, WEP_ELECTRO, trace_endpos, force * frametime);
169         }
170
171         // draw effect
172         vector vecs, org;
173         if(self.owner.weaponentity.movedir_x > 0)
174         {
175                 vecs = self.owner.weaponentity.movedir;
176                 vecs_y = -vecs_y;
177         }
178         else
179                 vecs = '0 0 0';
180         org = self.owner.origin + self.owner.view_ofs + v_forward * vecs_x + v_right * vecs_y + v_up * vecs_z;
181         
182         if(org != self.hook_start)
183         {
184                 self.SendFlags |= 2;
185                 self.hook_start = org;
186         }
187         if(trace_endpos != self.hook_end)
188         {
189                 self.SendFlags |= 4;
190                 self.hook_end = trace_endpos;
191         }
192 }
193
194 // experimental gauntlet
195 void W_Laser_Attack2 (float issecondary)
196 {
197         // only play fire sound if 0.5 sec has passed since player let go the fire button
198         if(time - self.prevgauntletfire > 0.5)
199         {
200                 sound (self, CHAN_WEAPON, "weapons/gauntlet_fire.wav", VOL_BASE, ATTN_NORM);
201         }
202
203         entity beam, oldself;
204
205         self.gauntletbeam = beam = spawn();
206         beam.solid = SOLID_NOT;
207         beam.think = gauntletbeam_think;
208         beam.owner = self;
209         beam.movetype = MOVETYPE_NONE;
210         beam.shot_spread = 0;
211         beam.bot_dodge = TRUE;
212         beam.bot_dodgerating = cvar("g_balance_laser_primary_damage");
213         beam.cnt = issecondary;
214         Net_LinkEntity(beam, FALSE, 0, gauntletbeam_send);
215
216         oldself = self;
217         self = beam;
218         self.think();
219         self = oldself;
220 }
221
222 void LaserInit()
223 {
224         weapon_action(WEP_LASER, WR_PRECACHE);
225         gauntlet_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 1);
226         gauntlet_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 2);
227         gauntlet_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 3);
228         gauntlet_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 4);
229 }
230
231 void spawnfunc_weapon_laser (void)
232 {
233         weapon_defaultspawnfunc(WEP_LASER);
234 }
235
236 float w_laser(float req)
237 {
238         local float r1;
239         local float r2;
240         if (req == WR_AIM)
241         {
242                 if(cvar("g_balance_laser_secondary"))
243                 {
244                         r1 = cvar("g_balance_laser_primary_damage");
245                         r2 = cvar("g_balance_laser_secondary_damage");
246                         if (random() * (r2 + r1) > r1)
247                                 self.BUTTON_ATCK2 = bot_aim(cvar("g_balance_laser_secondary_speed"), 0, cvar("g_balance_laser_secondary_lifetime"), FALSE);
248                         else
249                                 self.BUTTON_ATCK = bot_aim(cvar("g_balance_laser_primary_speed"), 0, cvar("g_balance_laser_primary_lifetime"), FALSE);
250                 }
251                 else
252                         self.BUTTON_ATCK = bot_aim(cvar("g_balance_laser_primary_speed"), 0, cvar("g_balance_laser_primary_lifetime"), FALSE);
253         }
254         else if (req == WR_THINK)
255         {
256                 if (self.BUTTON_ATCK)
257                 if (weapon_prepareattack(0, cvar("g_balance_laser_primary_refire")))
258                 {
259                         if(cvar("g_balance_laser_primary_gauntlet"))
260                                 W_Laser_Attack2(0);
261                         else
262                                 W_Laser_Attack(0);
263                         weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_laser_primary_animtime"), w_ready);
264                 }
265                 if (self.BUTTON_ATCK2)
266                 {
267                         if(cvar("g_balance_laser_secondary"))
268                         {
269                                 if (weapon_prepareattack(0, cvar("g_balance_laser_secondary_refire")))
270                                 {
271                                         if(cvar("g_balance_laser_secondary_gauntlet"))
272                                                 W_Laser_Attack2(1);
273                                         else
274                                                 W_Laser_Attack(1);
275                                         weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_laser_secondary_animtime"), w_ready);
276                                 }
277                         }
278                         else
279                         {
280                                 if(self.switchweapon == WEP_LASER) // don't do this if already switching
281                                         W_SwitchWeapon (self.cnt);
282                         }
283                 }
284         }
285         else if (req == WR_PRECACHE)
286         {
287                 precache_model ("models/weapons/g_laser.md3");
288                 precache_model ("models/weapons/v_laser.md3");
289                 precache_model ("models/weapons/h_laser.iqm");
290                 precache_sound ("weapons/lasergun_fire.wav");
291                 precache_sound ("weapons/gauntlet_fire.wav");
292         }
293         else if (req == WR_SETUP)
294                 weapon_setup(WEP_LASER);
295         else if (req == WR_CHECKAMMO1)
296                 return TRUE;
297         else if (req == WR_CHECKAMMO2)
298                 return TRUE;
299         return TRUE;
300 };
301 #endif
302 #ifdef CSQC
303 float w_laser(float req)
304 {
305         if(req == WR_IMPACTEFFECT)
306         {
307                 vector org2;
308                 org2 = w_org + w_backoff * 6;
309                 pointparticles(particleeffectnum("laser_impact"), org2, w_backoff * 1000, 1);
310                 if(!w_issilent)
311                         sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
312         }
313         else if(req == WR_PRECACHE)
314         {
315                 precache_sound("weapons/laserimpact.wav");
316         }
317         else if (req == WR_SUICIDEMESSAGE)
318                 w_deathtypestring = "lasered themself to hell";
319         else if (req == WR_KILLMESSAGE)
320         {
321                 w_deathtypestring = "was lasered to death by"; // unchecked: SPLASH
322         }
323         return TRUE;
324 }
325 #endif
326 #endif