Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
laser.qc
Go to the documentation of this file.
1#include "laser.qh"
2#if defined(CSQC)
5#elif defined(MENUQC)
6#elif defined(SVQC)
7#endif
8
9REGISTER_NET_LINKED(ENT_CLIENT_LASER)
10
11#ifdef SVQC
13{
14 vector a;
15 if(this.enemy)
16 {
17 if(this.spawnflags & LASER_FINITE)
18 {
19 if(this.enemy.origin != this.mangle)
20 {
21 this.mangle = this.enemy.origin;
23 }
24 }
25 else
26 {
27 a = vectoangles(this.enemy.origin - this.origin);
28 a_x = -a_x;
29 if(a != this.mangle)
30 {
31 this.mangle = a;
33 }
34 }
35 }
36 else
37 {
38 if(this.angles != this.mangle)
39 {
40 this.mangle = this.angles;
42 }
43 }
44 if(this.origin != this.oldorigin)
45 {
47 this.oldorigin = this.origin;
48 }
49}
50
52{
53 if(this.target != "")
54 this.enemy = find(NULL, targetname, this.target);
55}
56
57.entity pusher;
59{
60 vector o;
61 entity hitent;
62 vector hitloc;
63
64 this.nextthink = time;
65
66 if(this.active == ACTIVE_NOT)
67 return;
68
69 misc_laser_aim(this);
70
71 if(this.enemy)
72 {
73 o = this.enemy.origin;
74 if (!(this.spawnflags & LASER_FINITE))
75 o = this.origin + normalize(o - this.origin) * LASER_BEAM_MAXLENGTH;
76 }
77 else
78 {
79 makevectors(this.mangle);
81 }
82
83 if(this.dmg || this.enemy.target != "")
84 {
85 traceline(this.origin, o, MOVE_NORMAL, this);
86 }
87 hitent = trace_ent;
88 hitloc = trace_endpos;
89
90 if(this.enemy.target != "") // DETECTOR laser
91 {
92 if(trace_ent.iscreature)
93 {
94 this.pusher = hitent;
95 if(!this.count)
96 {
97 this.count = 1;
98
99 SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
100 }
101 }
102 else
103 {
104 if(this.count)
105 {
106 this.count = 0;
107
108 SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
109 }
110 }
111 }
112
113 if(this.dmg)
114 {
115 if(this.team)
116 if(((this.spawnflags & LASER_INVERT_TEAM) == 0) == (this.team != hitent.team))
117 return;
118 if(hitent.takedamage)
119 Damage(hitent, this, this, ((this.dmg < 0) ? 100000 : (this.dmg * frametime)), DEATH_HURTTRIGGER.m_id, DMG_NOWEP, hitloc, '0 0 0');
120 }
121}
122
123bool laser_SendEntity(entity this, entity to, float sendflags)
124{
125 WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
126 sendflags &= 0x0F; // use that bit to indicate finite length laser
127 if(this.spawnflags & LASER_FINITE)
128 sendflags |= SF_LASER_FINITE;
129 if(this.alpha)
130 sendflags |= SF_LASER_ALPHA;
131 if(this.scale != 1 || this.modelscale != 1)
132 sendflags |= SF_LASER_SCALE;
133 if(this.spawnflags & LASER_NOTRACE)
134 sendflags |= SF_LASER_NOTRACE;
135 WriteByte(MSG_ENTITY, sendflags);
136 if(sendflags & SF_LASER_UPDATE_ORIGIN)
137 {
138 WriteVector(MSG_ENTITY, this.origin);
139 }
140 if(sendflags & SF_LASER_UPDATE_EFFECT)
141 {
142 WriteByte(MSG_ENTITY, this.beam_color.x * 255.0);
143 WriteByte(MSG_ENTITY, this.beam_color.y * 255.0);
144 WriteByte(MSG_ENTITY, this.beam_color.z * 255.0);
145 if(sendflags & SF_LASER_ALPHA)
146 WriteByte(MSG_ENTITY, this.alpha * 255.0);
147 if(sendflags & SF_LASER_SCALE)
148 {
149 WriteByte(MSG_ENTITY, bound(0, this.scale * 16.0, 255));
150 WriteByte(MSG_ENTITY, bound(0, this.modelscale * 16.0, 255));
151 }
152 if((sendflags & SF_LASER_FINITE) || !(sendflags & SF_LASER_NOTRACE)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
154 }
155 if(sendflags & SF_LASER_UPDATE_TARGET)
156 {
157 if(sendflags & SF_LASER_FINITE)
158 {
159 WriteVector(MSG_ENTITY, this.enemy.origin);
160 }
161 else
162 {
163 WriteAngleVector2D(MSG_ENTITY, this.mangle);
164 }
165 }
166 if(sendflags & SF_LASER_UPDATE_ACTIVE)
168 return true;
169}
170
171/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
172Any object touching the beam will be hurt
173Keys:
174"target"
175 spawnfunc_target_position where the laser ends
176"mdl"
177 name of beam end effect to use
178"beam_color"
179 color of the beam (default: red)
180"dmg"
181 damage per second (-1 for a laser that kills immediately)
182*/
183
184void laser_setactive(entity this, int act)
185{
186 int old_status = this.active;
187 if(act == ACTIVE_TOGGLE)
188 {
189 if(this.active == ACTIVE_ACTIVE)
190 {
191 this.active = ACTIVE_NOT;
192 }
193 else
194 {
195 this.active = ACTIVE_ACTIVE;
196 }
197 }
198 else
199 {
200 this.active = act;
201 }
202
203 if (this.active != old_status)
204 {
206 misc_laser_aim(this);
207 }
208}
209
210void laser_use(entity this, entity actor, entity trigger)
211{
212 this.setactive(this, ACTIVE_TOGGLE);
213}
214
215spawnfunc(misc_laser)
216{
217 if(this.mdl)
218 {
219 if(this.mdl == "none")
220 this.cnt = -1;
221 else
222 {
223 this.cnt = _particleeffectnum(this.mdl);
224 if(this.cnt < 0 && this.dmg)
225 this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
226 }
227 }
228 else if(!this.cnt)
229 {
230 if(this.dmg)
231 this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
232 else
233 this.cnt = -1;
234 }
235 if(this.cnt < 0)
236 this.cnt = -1;
237
238 if(!this.beam_color && this.colormod)
239 {
240 LOG_WARN("misc_laser uses legacy field 'colormod', please use 'beam_color' instead");
241 this.beam_color = this.colormod;
242 }
243
244 if(this.beam_color == '0 0 0')
245 {
246 if(!this.alpha)
247 this.beam_color = '1 0 0';
248 }
249
250 if(this.message == "")
251 {
252 this.message = "saw the light";
253 }
254 if (this.message2 == "")
255 {
256 this.message2 = "was pushed into a laser by";
257 }
258 if(!this.scale)
259 {
260 this.scale = 1;
261 }
262 if(!this.modelscale)
263 {
264 this.modelscale = 1;
265 }
266 else if(this.modelscale < 0)
267 {
268 this.modelscale = 0;
269 }
271 this.nextthink = time;
273
274 this.mangle = this.angles;
275
276 Net_LinkEntity(this, false, 0, laser_SendEntity);
277
278 this.setactive = laser_setactive;
279
280 if(this.targetname && this.targetname != "")
281 {
282 // backwards compatibility
283 this.use = laser_use;
284 }
285
286 this.reset = generic_netlinked_reset;
287 this.reset(this);
288}
289#elif defined(CSQC)
290
291void Draw_Laser(entity this)
292{
293 if(this.active == ACTIVE_NOT)
294 return;
296 if(this.count & SF_LASER_FINITE)
297 {
298 if(this.count & SF_LASER_NOTRACE)
299 {
300 trace_endpos = this.velocity;
302 }
303 else
304 traceline(this.origin, this.velocity, 0, this);
305 }
306 else
307 {
308 if(this.count & SF_LASER_NOTRACE)
309 {
310 makevectors(this.angles);
313 }
314 else
315 {
316 makevectors(this.angles);
317 traceline(this.origin, this.origin + v_forward * LASER_BEAM_MAXLENGTH, 0, this);
320 }
321 }
322 if(this.scale != 0)
323 {
324 if(this.alpha)
325 {
326 Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, this.alpha, DRAWFLAG_NORMAL, view_origin);
327 }
328 else
329 {
330 Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, 0.5, DRAWFLAG_ADDITIVE, view_origin);
331 }
332 }
334 {
335 if(this.cnt >= 0)
336 __pointparticles(this.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
337 if(this.beam_color != '0 0 0' && this.modelscale != 0)
339 }
340}
341
342NET_HANDLE(ENT_CLIENT_LASER, bool isnew)
343{
345
346 // 30 bytes, or 13 bytes for just moving
347 int sendflags = ReadByte();
348 this.count = (sendflags & 0xF0);
349
350 if(this.count & SF_LASER_FINITE)
352 else
354
355 if(sendflags & SF_LASER_UPDATE_ORIGIN)
356 {
357 this.origin = ReadVector();
358 setorigin(this, this.origin);
359 }
360 if(sendflags & SF_LASER_UPDATE_EFFECT)
361 {
362 this.beam_color.x = ReadByte() / 255.0;
363 this.beam_color.y = ReadByte() / 255.0;
364 this.beam_color.z = ReadByte() / 255.0;
365 if(sendflags & SF_LASER_ALPHA)
366 this.alpha = ReadByte() / 255.0;
367 else
368 this.alpha = 0;
369 this.scale = 2; // NOTE: why 2?
370 this.modelscale = 50; // NOTE: why 50?
371 if(sendflags & SF_LASER_SCALE)
372 {
373 this.scale *= ReadByte() / 16.0; // beam radius
374 this.modelscale *= ReadByte() / 16.0; // dlight radius
375 }
376 if((sendflags & SF_LASER_FINITE) || !(sendflags & SF_LASER_NOTRACE))
377 this.cnt = ReadShort(); // effect number
378 else
379 this.cnt = 0;
380 }
381 if(sendflags & SF_LASER_UPDATE_TARGET)
382 {
383 if(sendflags & SF_LASER_FINITE)
384 {
385 this.velocity = ReadVector();
386 }
387 else
388 {
389 this.angles = ReadAngleVector2D();
390 }
391 }
392 if(sendflags & SF_LASER_UPDATE_ACTIVE)
393 this.active = ReadByte();
394
395 return = true;
396
398 this.draw = Draw_Laser;
399 if (isnew) IL_PUSH(g_drawables, this);
400}
401#endif
float dmg
Definition breakable.qc:12
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float cnt
Definition powerups.qc:24
string message
Definition powerups.qc:19
vector colormod
Definition powerups.qc:21
float count
Definition powerups.qc:22
float alpha
Definition items.qc:13
IntrusiveList g_drawables
Definition main.qh:91
vector view_origin
Definition main.qh:109
float drawframetime
Definition main.qh:108
int team
Definition main.qh:188
int spawnflags
Definition ammo.qh:15
string mdl
Definition item.qh:89
void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg)
Definition draw.qh:10
const int INITPRIO_FINDTARGET
Definition constants.qh:96
float Q3SURFACEFLAG_SKY
const float DRAWFLAG_NORMAL
entity trace_ent
const float DRAWFLAG_ADDITIVE
float frametime
const float MOVE_NORMAL
vector velocity
float time
vector trace_endpos
float nextthink
float trace_dphitq3surfaceflags
vector v_forward
vector origin
vector oldorigin
float Q3SURFACEFLAG_NOIMPACT
vector trace_plane_normal
#define use
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:493
#define DMG_NOWEP
Definition damage.qh:104
const int ACTIVE_TOGGLE
Definition defs.qh:40
const int ACTIVE_NOT
Definition defs.qh:36
int active
Definition defs.qh:34
const int ACTIVE_ACTIVE
Definition defs.qh:37
#define particleeffectnum(e)
Definition effect.qh:3
ent angles
Definition ent_cs.qc:146
WriteByte(chan, ent.angles.y/DEC_FACTOR)
void InterpolateOrigin_Undo(entity this)
snap origin to iorigin2 (actual origin)
void InterpolateOrigin_Note(entity this)
void InterpolateOrigin_Do(entity this)
set origin based on iorigin1 (old pos), iorigin2 (desired pos), and time
const int IFLAG_VELOCITY
const int IFLAG_ANGLES
const int IFLAG_ORIGIN
int iflags
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition triggers.qc:344
void misc_laser_aim(entity this)
Definition laser.qc:12
void misc_laser_think(entity this)
Definition laser.qc:58
void laser_setactive(entity this, int act)
Definition laser.qc:184
entity pusher
Definition laser.qc:57
bool laser_SendEntity(entity this, entity to, float sendflags)
Definition laser.qc:123
void laser_use(entity this, entity actor, entity trigger)
Definition laser.qc:210
void misc_laser_init(entity this)
Definition laser.qc:51
const int LASER_NOTRACE
Definition laser.qh:17
const int SF_LASER_NOTRACE
Definition laser.qh:25
const int SF_LASER_FINITE
Definition laser.qh:28
const float LASER_BEAM_MAXLENGTH
Definition laser.qh:32
vector beam_color
Definition laser.qh:30
const float LASER_BEAM_MAXWORLDSIZE
Definition laser.qh:34
const int SF_LASER_UPDATE_EFFECT
Definition laser.qh:23
const int SF_LASER_UPDATE_ACTIVE
Definition laser.qh:22
const int SF_LASER_UPDATE_TARGET
Definition laser.qh:21
const int LASER_FINITE
Definition laser.qh:16
const int SF_LASER_ALPHA
Definition laser.qh:27
const int SF_LASER_UPDATE_ORIGIN
Definition laser.qh:20
const int LASER_INVERT_TEAM
Definition laser.qh:18
const int SF_LASER_SCALE
Definition laser.qh:26
int SendFlags
Definition net.qh:159
#define NET_HANDLE(id, param)
Definition net.qh:15
const int MSG_ENTITY
Definition net.qh:156
#define ReadVector()
Definition net.qh:349
#define WriteHeader(to, id)
Definition net.qh:265
#define REGISTER_NET_LINKED(id)
Definition net.qh:91
#define ReadAngleVector2D()
Definition net.qh:352
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
Definition net.qh:167
int ReadByte()
#define LOG_WARN(...)
Definition log.qh:58
float bound(float min, float value, float max)
entity find(entity start,.string field, string match)
void WriteShort(float data, float dest, float desto)
vector vectoangles(vector v)
vector normalize(vector v)
float modelscale
Definition models.qh:3
#define NULL
Definition post.qh:14
#define makevectors
Definition post.qh:21
#define adddynamiclight
Definition post.qh:29
float scale
Definition projectile.qc:14
#define setthink(e, f)
vector
Definition self.qh:96
#define spawnfunc(id)
Definition spawnfunc.qh:107
vector mangle
Definition subs.qh:51
entity enemy
Definition sv_ctf.qh:152
void generic_netlinked_reset(entity this)
Definition triggers.qc:76
string message2
Definition triggers.qh:19
string targetname
Definition triggers.qh:56
string target
Definition triggers.qh:55
void InitializeEntity(entity e, void(entity this) func, int order)
Definition world.qc:2229