3 #include <lib/csqcmodel/interpolate.qh>
4 #include <client/main.qh>
5 #include <lib/csqcmodel/cl_model.qh>
10 REGISTER_NET_LINKED(ENT_CLIENT_LASER)
14 void misc_laser_aim(entity this)
19 if(this.spawnflags & LASER_FINITE)
21 if(this.enemy.origin != this.mangle)
23 this.mangle = this.enemy.origin;
24 this.SendFlags |= SF_LASER_UPDATE_TARGET;
29 a = vectoangles(this.enemy.origin - this.origin);
34 this.SendFlags |= SF_LASER_UPDATE_TARGET;
40 if(this.angles != this.mangle)
42 this.mangle = this.angles;
43 this.SendFlags |= SF_LASER_UPDATE_TARGET;
46 if(this.origin != this.oldorigin)
48 this.SendFlags |= SF_LASER_UPDATE_ORIGIN;
49 this.oldorigin = this.origin;
53 void misc_laser_init(entity this)
56 this.enemy = find(NULL, targetname, this.target);
60 void misc_laser_think(entity this)
66 this.nextthink = time;
68 if(this.active == ACTIVE_NOT)
75 o = this.enemy.origin;
76 if (!(this.spawnflags & LASER_FINITE))
77 o = this.origin + normalize(o - this.origin) * LASER_BEAM_MAXLENGTH;
81 makevectors(this.mangle);
82 o = this.origin + v_forward * LASER_BEAM_MAXLENGTH;
85 if(this.dmg || this.enemy.target != "")
87 traceline(this.origin, o, MOVE_NORMAL, this);
90 hitloc = trace_endpos;
92 if(this.enemy.target != "") // DETECTOR laser
94 if(trace_ent.iscreature)
101 SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
110 SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
118 if(((this.spawnflags & LASER_INVERT_TEAM) == 0) == (this.team != hitent.team))
120 if(hitent.takedamage)
121 Damage(hitent, this, this, ((this.dmg < 0) ? 100000 : (this.dmg * frametime)), DEATH_HURTTRIGGER.m_id, DMG_NOWEP, hitloc, '0 0 0');
125 bool laser_SendEntity(entity this, entity to, float sendflags)
127 WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
128 sendflags = sendflags & 0x0F; // use that bit to indicate finite length laser
129 if(this.spawnflags & LASER_FINITE)
130 sendflags |= SF_LASER_FINITE;
132 sendflags |= SF_LASER_ALPHA;
133 if(this.scale != 1 || this.modelscale != 1)
134 sendflags |= SF_LASER_SCALE;
135 if(this.spawnflags & LASER_NOTRACE)
136 sendflags |= SF_LASER_NOTRACE;
137 WriteByte(MSG_ENTITY, sendflags);
138 if(sendflags & SF_LASER_UPDATE_ORIGIN)
140 WriteVector(MSG_ENTITY, this.origin);
142 if(sendflags & SF_LASER_UPDATE_EFFECT)
144 WriteByte(MSG_ENTITY, this.beam_color.x * 255.0);
145 WriteByte(MSG_ENTITY, this.beam_color.y * 255.0);
146 WriteByte(MSG_ENTITY, this.beam_color.z * 255.0);
147 if(sendflags & SF_LASER_ALPHA)
148 WriteByte(MSG_ENTITY, this.alpha * 255.0);
149 if(sendflags & SF_LASER_SCALE)
151 WriteByte(MSG_ENTITY, bound(0, this.scale * 16.0, 255));
152 WriteByte(MSG_ENTITY, bound(0, this.modelscale * 16.0, 255));
154 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
155 WriteShort(MSG_ENTITY, this.cnt);
157 if(sendflags & SF_LASER_UPDATE_TARGET)
159 if(sendflags & SF_LASER_FINITE)
161 WriteVector(MSG_ENTITY, this.enemy.origin);
165 WriteAngle(MSG_ENTITY, this.mangle_x);
166 WriteAngle(MSG_ENTITY, this.mangle_y);
169 if(sendflags & SF_LASER_UPDATE_ACTIVE)
170 WriteByte(MSG_ENTITY, this.active);
174 /*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
175 Any object touching the beam will be hurt
178 spawnfunc_target_position where the laser ends
180 name of beam end effect to use
182 color of the beam (default: red)
184 damage per second (-1 for a laser that kills immediately)
187 void laser_setactive(entity this, int act)
189 int old_status = this.active;
190 if(act == ACTIVE_TOGGLE)
192 if(this.active == ACTIVE_ACTIVE)
194 this.active = ACTIVE_NOT;
198 this.active = ACTIVE_ACTIVE;
206 if (this.active != old_status)
208 this.SendFlags |= SF_LASER_UPDATE_ACTIVE;
209 misc_laser_aim(this);
213 void laser_use(entity this, entity actor, entity trigger)
215 this.setactive(this, ACTIVE_TOGGLE);
218 spawnfunc(misc_laser)
222 if(this.mdl == "none")
226 this.cnt = _particleeffectnum(this.mdl);
227 if(this.cnt < 0 && this.dmg)
228 this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
234 this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
241 if(!this.beam_color && this.colormod)
243 LOG_WARN("misc_laser uses legacy field 'colormod', please use 'beam_color' instead");
244 this.beam_color = this.colormod;
247 if(this.beam_color == '0 0 0')
250 this.beam_color = '1 0 0';
253 if(this.message == "")
255 this.message = "saw the light";
257 if (this.message2 == "")
259 this.message2 = "was pushed into a laser by";
269 else if(this.modelscale < 0)
273 setthink(this, misc_laser_think);
274 this.nextthink = time;
275 InitializeEntity(this, misc_laser_init, INITPRIO_FINDTARGET);
277 this.mangle = this.angles;
279 Net_LinkEntity(this, false, 0, laser_SendEntity);
281 this.setactive = laser_setactive;
285 // backwards compatibility
286 this.use = laser_use;
289 this.reset = generic_netlinked_reset;
294 // a laser goes from origin in direction angles
295 // it has color 'beam_color'
296 // and stops when something is in the way
298 classfield(Laser) .int cnt; // end effect
299 classfield(Laser) .vector colormod;
300 classfield(Laser) .int state; // on-off
301 classfield(Laser) .int count; // flags for the laser
302 classfield(Laser) .vector velocity; // laser endpoint if it is FINITE
303 classfield(Laser) .float alpha;
304 classfield(Laser) .float scale; // scaling factor of the thickness
305 classfield(Laser) .float modelscale; // scaling factor of the dlight
307 void Draw_Laser(entity this)
309 if(this.active == ACTIVE_NOT)
311 InterpolateOrigin_Do(this);
312 if(this.count & SF_LASER_FINITE)
314 if(this.count & SF_LASER_NOTRACE)
316 trace_endpos = this.velocity;
317 trace_dphitq3surfaceflags = 0;
320 traceline(this.origin, this.velocity, 0, this);
324 if(this.count & SF_LASER_NOTRACE)
326 makevectors(this.angles);
327 trace_endpos = this.origin + v_forward * LASER_BEAM_MAXWORLDSIZE;
328 trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
332 makevectors(this.angles);
333 traceline(this.origin, this.origin + v_forward * LASER_BEAM_MAXLENGTH, 0, this);
334 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
335 trace_endpos = this.origin + v_forward * LASER_BEAM_MAXWORLDSIZE;
342 Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, this.alpha, DRAWFLAG_NORMAL, view_origin);
346 Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, 0.5, DRAWFLAG_ADDITIVE, view_origin);
349 if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
352 __pointparticles(this.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
353 if(this.beam_color != '0 0 0' && this.modelscale != 0)
354 adddynamiclight(trace_endpos + trace_plane_normal * 1, this.modelscale, this.beam_color * 5);
358 NET_HANDLE(ENT_CLIENT_LASER, bool isnew)
360 InterpolateOrigin_Undo(this);
362 // 30 bytes, or 13 bytes for just moving
363 int sendflags = ReadByte();
364 this.count = (sendflags & 0xF0);
366 if(this.count & SF_LASER_FINITE)
367 this.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
369 this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
371 if(sendflags & SF_LASER_UPDATE_ORIGIN)
373 this.origin = ReadVector();
374 setorigin(this, this.origin);
376 if(sendflags & SF_LASER_UPDATE_EFFECT)
378 this.beam_color.x = ReadByte() / 255.0;
379 this.beam_color.y = ReadByte() / 255.0;
380 this.beam_color.z = ReadByte() / 255.0;
381 if(sendflags & SF_LASER_ALPHA)
382 this.alpha = ReadByte() / 255.0;
385 this.scale = 2; // NOTE: why 2?
386 this.modelscale = 50; // NOTE: why 50?
387 if(sendflags & SF_LASER_SCALE)
389 this.scale *= ReadByte() / 16.0; // beam radius
390 this.modelscale *= ReadByte() / 16.0; // dlight radius
392 if((sendflags & SF_LASER_FINITE) || !(sendflags & SF_LASER_NOTRACE))
393 this.cnt = ReadShort(); // effect number
397 if(sendflags & SF_LASER_UPDATE_TARGET)
399 if(sendflags & SF_LASER_FINITE)
401 this.velocity = ReadVector();
405 this.angles_x = ReadAngle();
406 this.angles_y = ReadAngle();
409 if(sendflags & SF_LASER_UPDATE_ACTIVE)
410 this.active = ReadByte();
414 InterpolateOrigin_Note(this);
415 this.draw = Draw_Laser;
416 if (isnew) IL_PUSH(g_drawables, this);