]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_laser.qc
Merge branch 'master' into divVerent/fruitbalance
[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 .entity gauntletbeam;
105 .float prevgauntletfire;
106 void gauntletbeam_think()
107 {
108         float damage, myforce, myradius;
109         if(self.cnt)
110         {
111                 damage = cvar("g_balance_laser_secondary_damage");
112                 myforce = cvar("g_balance_laser_secondary_force");
113                 myradius = cvar("g_balance_laser_secondary_radius");
114         }
115         else
116         {
117                 damage = cvar("g_balance_laser_primary_damage");
118                 myforce = cvar("g_balance_laser_primary_force");
119                 myradius = cvar("g_balance_laser_primary_radius");
120         }
121
122         self.owner.prevgauntletfire = time;
123         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))
124         {
125                 remove(self);
126                 return;
127         }
128
129         self.nextthink = time;
130
131         makevectors(self.owner.v_angle);
132         vector angle;
133         angle = v_forward;
134
135         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));
136
137         // apply the damage
138         if(trace_fraction < 1)
139         {
140                 vector force;
141                 force = angle * myforce;
142                 Damage (trace_ent, self.owner, self.owner, damage * frametime, WEP_ELECTRO, trace_endpos, force * frametime);
143         }
144
145         // draw effect
146         vector vecs, org;
147         if(self.owner.weaponentity.movedir_x > 0)
148         {
149                 vecs = self.owner.weaponentity.movedir;
150                 vecs_y = -vecs_y;
151         }
152         else
153                 vecs = '0 0 0';
154         org = self.owner.origin + self.owner.view_ofs + v_forward * vecs_x + v_right * vecs_y + v_up * vecs_z;
155         
156         // TODO turn into a csqc entity
157         WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
158         WriteByte(MSG_BROADCAST, TE_CSQC_BEAM);
159         WriteByte(MSG_BROADCAST, num_for_edict(self.owner));
160         WriteByte(MSG_BROADCAST, 3);
161         WriteCoord(MSG_BROADCAST, trace_endpos_x);
162         WriteCoord(MSG_BROADCAST, trace_endpos_y);
163         WriteCoord(MSG_BROADCAST, trace_endpos_z);
164         WriteCoord(MSG_BROADCAST, org_x);
165         WriteCoord(MSG_BROADCAST, org_y);
166         WriteCoord(MSG_BROADCAST, org_z);
167 }
168
169 // experimental gauntlet
170 void W_Laser_Attack2 (float issecondary)
171 {
172         // only play fire sound if 0.5 sec has passed since player let go the fire button
173         if(time - self.prevgauntletfire > 0.5)
174         {
175                 sound (self, CHAN_WEAPON, "weapons/gauntlet_fire.wav", VOL_BASE, ATTN_NORM);
176         }
177
178         entity beam, oldself;
179
180         self.gauntletbeam = beam = spawn();
181         beam.solid = SOLID_NOT;
182         beam.think = gauntletbeam_think;
183         beam.owner = self;
184         beam.movetype = MOVETYPE_NONE;
185         beam.shot_spread = 0;
186         beam.bot_dodge = TRUE;
187         beam.bot_dodgerating = cvar("g_balance_laser_primary_damage");
188         beam.cnt = issecondary;
189
190         oldself = self;
191         self = beam;
192         self.think();
193         self = oldself;
194 }
195
196 void LaserInit()
197 {
198         weapon_action(WEP_LASER, WR_PRECACHE);
199         gauntlet_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 1);
200         gauntlet_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 2);
201         gauntlet_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 3);
202         gauntlet_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_LASER), FALSE, FALSE, 4);
203 }
204
205 void spawnfunc_weapon_laser (void)
206 {
207         weapon_defaultspawnfunc(WEP_LASER);
208 }
209
210 float w_laser(float req)
211 {
212         local float r1;
213         local float r2;
214         if (req == WR_AIM)
215         {
216                 if(cvar("g_balance_laser_secondary"))
217                 {
218                         r1 = cvar("g_balance_laser_primary_damage");
219                         r2 = cvar("g_balance_laser_secondary_damage");
220                         if (random() * (r2 + r1) > r1)
221                                 self.BUTTON_ATCK2 = bot_aim(cvar("g_balance_laser_secondary_speed"), 0, cvar("g_balance_laser_secondary_lifetime"), FALSE);
222                         else
223                                 self.BUTTON_ATCK = bot_aim(cvar("g_balance_laser_primary_speed"), 0, cvar("g_balance_laser_primary_lifetime"), FALSE);
224                 }
225                 else
226                         self.BUTTON_ATCK = bot_aim(cvar("g_balance_laser_primary_speed"), 0, cvar("g_balance_laser_primary_lifetime"), FALSE);
227         }
228         else if (req == WR_THINK)
229         {
230                 if (self.BUTTON_ATCK)
231                 if (weapon_prepareattack(0, cvar("g_balance_laser_primary_refire")))
232                 {
233                         if(cvar("g_balance_laser_primary_gauntlet"))
234                                 W_Laser_Attack2(0);
235                         else
236                                 W_Laser_Attack(0);
237                         weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_laser_primary_animtime"), w_ready);
238                 }
239                 if (self.BUTTON_ATCK2)
240                 {
241                         if(cvar("g_balance_laser_secondary"))
242                         {
243                                 if (weapon_prepareattack(0, cvar("g_balance_laser_secondary_refire")))
244                                 {
245                                         if(cvar("g_balance_laser_secondary_gauntlet"))
246                                                 W_Laser_Attack2(1);
247                                         else
248                                                 W_Laser_Attack(1);
249                                         weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_laser_secondary_animtime"), w_ready);
250                                 }
251                         }
252                         else
253                         {
254                                 if(self.switchweapon == WEP_LASER) // don't do this if already switching
255                                         W_SwitchWeapon (self.cnt);
256                         }
257                 }
258         }
259         else if (req == WR_PRECACHE)
260         {
261                 precache_model ("models/weapons/g_laser.md3");
262                 precache_model ("models/weapons/v_laser.md3");
263                 precache_model ("models/weapons/h_laser.iqm");
264                 precache_sound ("weapons/lasergun_fire.wav");
265                 precache_sound ("weapons/gauntlet_fire.wav");
266         }
267         else if (req == WR_SETUP)
268                 weapon_setup(WEP_LASER);
269         else if (req == WR_CHECKAMMO1)
270                 return TRUE;
271         else if (req == WR_CHECKAMMO2)
272                 return TRUE;
273         return TRUE;
274 };
275 #endif
276 #ifdef CSQC
277 float w_laser(float req)
278 {
279         if(req == WR_IMPACTEFFECT)
280         {
281                 vector org2;
282                 org2 = w_org + w_backoff * 6;
283                 pointparticles(particleeffectnum("laser_impact"), org2, w_backoff * 1000, 1);
284                 if(!w_issilent)
285                         sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
286         }
287         else if(req == WR_PRECACHE)
288         {
289                 precache_sound("weapons/laserimpact.wav");
290         }
291         else if (req == WR_SUICIDEMESSAGE)
292                 w_deathtypestring = "lasered themself to hell";
293         else if (req == WR_KILLMESSAGE)
294         {
295                 w_deathtypestring = "was lasered to death by"; // unchecked: SPLASH
296         }
297         return TRUE;
298 }
299 #endif
300 #endif