]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/misc/laser.qc
Merge branch 'TimePath/experiments/csqc_prediction' into Mario/qc_physics
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / misc / laser.qc
1 #ifdef SVQC
2 .float modelscale;
3 void misc_laser_aim()
4 {
5         vector a;
6         if(self.enemy)
7         {
8                 if(self.spawnflags & 2)
9                 {
10                         if(self.enemy.origin != self.mangle)
11                         {
12                                 self.mangle = self.enemy.origin;
13                                 self.SendFlags |= 2;
14                         }
15                 }
16                 else
17                 {
18                         a = vectoangles(self.enemy.origin - self.origin);
19                         a_x = -a_x;
20                         if(a != self.mangle)
21                         {
22                                 self.mangle = a;
23                                 self.SendFlags |= 2;
24                         }
25                 }
26         }
27         else
28         {
29                 if(self.angles != self.mangle)
30                 {
31                         self.mangle = self.angles;
32                         self.SendFlags |= 2;
33                 }
34         }
35         if(self.origin != self.oldorigin)
36         {
37                 self.SendFlags |= 1;
38                 self.oldorigin = self.origin;
39         }
40 }
41
42 void misc_laser_init()
43 {
44         if(self.target != "")
45                 self.enemy = find(world, targetname, self.target);
46 }
47
48 .entity pusher;
49 void misc_laser_think()
50 {
51         vector o;
52         entity oldself;
53         entity hitent;
54         vector hitloc;
55
56         self.nextthink = time;
57
58         if(!self.state)
59                 return;
60
61         misc_laser_aim();
62
63         if(self.enemy)
64         {
65                 o = self.enemy.origin;
66                 if (!(self.spawnflags & 2))
67                         o = self.origin + normalize(o - self.origin) * 32768;
68         }
69         else
70         {
71                 makevectors(self.mangle);
72                 o = self.origin + v_forward * 32768;
73         }
74
75         if(self.dmg || self.enemy.target != "")
76         {
77                 traceline(self.origin, o, MOVE_NORMAL, self);
78         }
79         hitent = trace_ent;
80         hitloc = trace_endpos;
81
82         if(self.enemy.target != "") // DETECTOR laser
83         {
84                 if(trace_ent.iscreature)
85                 {
86                         self.pusher = hitent;
87                         if(!self.count)
88                         {
89                                 self.count = 1;
90
91                                 oldself = self;
92                                 self = self.enemy;
93                                 activator = self.pusher;
94                                 SUB_UseTargets();
95                                 self = oldself;
96                         }
97                 }
98                 else
99                 {
100                         if(self.count)
101                         {
102                                 self.count = 0;
103
104                                 oldself = self;
105                                 self = self.enemy;
106                                 activator = self.pusher;
107                                 SUB_UseTargets();
108                                 self = oldself;
109                         }
110                 }
111         }
112
113         if(self.dmg)
114         {
115                 if(self.team)
116                         if(((self.spawnflags & 8) == 0) == (self.team != hitent.team))
117                                 return;
118                 if(hitent.takedamage)
119                         Damage(hitent, self, self, ((self.dmg < 0) ? 100000 : (self.dmg * frametime)), DEATH_HURTTRIGGER, hitloc, '0 0 0');
120         }
121 }
122
123 float laser_SendEntity(entity to, float fl)
124 {
125         WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
126         fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
127         if(self.spawnflags & 2)
128                 fl |= 0x80;
129         if(self.alpha)
130                 fl |= 0x40;
131         if(self.scale != 1 || self.modelscale != 1)
132                 fl |= 0x20;
133         if(self.spawnflags & 4)
134                 fl |= 0x10;
135         WriteByte(MSG_ENTITY, fl);
136         if(fl & 1)
137         {
138                 WriteCoord(MSG_ENTITY, self.origin_x);
139                 WriteCoord(MSG_ENTITY, self.origin_y);
140                 WriteCoord(MSG_ENTITY, self.origin_z);
141         }
142         if(fl & 8)
143         {
144                 WriteByte(MSG_ENTITY, self.colormod_x * 255.0);
145                 WriteByte(MSG_ENTITY, self.colormod_y * 255.0);
146                 WriteByte(MSG_ENTITY, self.colormod_z * 255.0);
147                 if(fl & 0x40)
148                         WriteByte(MSG_ENTITY, self.alpha * 255.0);
149                 if(fl & 0x20)
150                 {
151                         WriteByte(MSG_ENTITY, bound(0, self.scale * 16.0, 255));
152                         WriteByte(MSG_ENTITY, bound(0, self.modelscale * 16.0, 255));
153                 }
154                 if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
155                         WriteShort(MSG_ENTITY, self.cnt + 1);
156         }
157         if(fl & 2)
158         {
159                 if(fl & 0x80)
160                 {
161                         WriteCoord(MSG_ENTITY, self.enemy.origin_x);
162                         WriteCoord(MSG_ENTITY, self.enemy.origin_y);
163                         WriteCoord(MSG_ENTITY, self.enemy.origin_z);
164                 }
165                 else
166                 {
167                         WriteAngle(MSG_ENTITY, self.mangle_x);
168                         WriteAngle(MSG_ENTITY, self.mangle_y);
169                 }
170         }
171         if(fl & 4)
172                 WriteByte(MSG_ENTITY, self.state);
173         return 1;
174 }
175
176 /*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
177 Any object touching the beam will be hurt
178 Keys:
179 "target"
180  spawnfunc_target_position where the laser ends
181 "mdl"
182  name of beam end effect to use
183 "colormod"
184  color of the beam (default: red)
185 "dmg"
186  damage per second (-1 for a laser that kills immediately)
187 */
188 void laser_use()
189 {
190         self.state = !self.state;
191         self.SendFlags |= 4;
192         misc_laser_aim();
193 }
194
195 void laser_reset()
196 {
197         if(self.spawnflags & 1)
198                 self.state = 1;
199         else
200                 self.state = 0;
201 }
202
203 void spawnfunc_misc_laser()
204 {
205         if(self.mdl)
206         {
207                 if(self.mdl == "none")
208                         self.cnt = -1;
209                 else
210                 {
211                         self.cnt = particleeffectnum(self.mdl);
212                         if(self.cnt < 0)
213                                 if(self.dmg)
214                                         self.cnt = particleeffectnum("laser_deadly");
215                 }
216         }
217         else if(!self.cnt)
218         {
219                 if(self.dmg)
220                         self.cnt = particleeffectnum("laser_deadly");
221                 else
222                         self.cnt = -1;
223         }
224         if(self.cnt < 0)
225                 self.cnt = -1;
226
227         if(self.colormod == '0 0 0')
228                 if(!self.alpha)
229                         self.colormod = '1 0 0';
230         if(self.message == "")
231                 self.message = "saw the light";
232         if (self.message2 == "")
233                 self.message2 = "was pushed into a laser by";
234         if(!self.scale)
235                 self.scale = 1;
236         if(!self.modelscale)
237                 self.modelscale = 1;
238         else if(self.modelscale < 0)
239                 self.modelscale = 0;
240         self.think = misc_laser_think;
241         self.nextthink = time;
242         InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET);
243
244         self.mangle = self.angles;
245
246         Net_LinkEntity(self, false, 0, laser_SendEntity);
247
248         IFTARGETED
249         {
250                 self.reset = laser_reset;
251                 laser_reset();
252                 self.use = laser_use;
253         }
254         else
255                 self.state = 1;
256 }
257 #endif