]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/trigger/impulse.qc
Merge branch 'master' into Mario/hagar_notfixed
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / trigger / impulse.qc
1 // targeted (directional) mode
2 void trigger_impulse_touch1()
3 {SELFPARAM();
4         entity targ;
5         float pushdeltatime;
6         float str;
7
8         if (self.active != ACTIVE_ACTIVE)
9                 return;
10
11         if (!isPushable(other))
12                 return;
13
14         EXACTTRIGGER_TOUCH;
15
16         targ = find(world, targetname, self.target);
17         if(!targ)
18         {
19                 objerror("trigger_force without a (valid) .target!\n");
20                 remove(self);
21                 return;
22         }
23
24 #ifdef SVQC
25         str = min(self.radius, vlen(self.origin - other.origin));
26 #elif defined(CSQC)
27         str = min(self.radius, vlen(self.origin - other.move_origin));
28 #endif
29
30         if(self.falloff == 1)
31                 str = (str / self.radius) * self.strength;
32         else if(self.falloff == 2)
33                 str = (1 - (str / self.radius)) * self.strength;
34         else
35                 str = self.strength;
36
37         pushdeltatime = time - other.lastpushtime;
38         if (pushdeltatime > 0.15) pushdeltatime = 0;
39         other.lastpushtime = time;
40         if(!pushdeltatime) return;
41
42         if(self.spawnflags & 64)
43         {
44 #ifdef SVQC
45                 float addspeed = str - other.velocity * normalize(targ.origin - self.origin);
46                 if (addspeed > 0)
47                 {
48                         float accelspeed = min(8 * pushdeltatime * str, addspeed);
49                         other.velocity += accelspeed * normalize(targ.origin - self.origin);
50                 }
51 #elif defined(CSQC)
52                 float addspeed = str - other.move_velocity * normalize(targ.origin - self.origin);
53                 if (addspeed > 0)
54                 {
55                         float accelspeed = min(8 * pushdeltatime * str, addspeed);
56                         other.move_velocity += accelspeed * normalize(targ.origin - self.origin);
57                 }
58 #endif
59         }
60         else
61 #ifdef SVQC
62                 other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime;
63 #elif defined(CSQC)
64                 other.move_velocity = other.move_velocity + normalize(targ.origin - self.origin) * str * pushdeltatime;
65 #endif
66
67 #ifdef SVQC
68         UNSET_ONGROUND(other);
69
70         UpdateCSQCProjectile(other);
71 #elif defined(CSQC)
72         other.move_flags &= ~FL_ONGROUND;
73 #endif
74 }
75
76 // Directionless (accelerator/decelerator) mode
77 void trigger_impulse_touch2()
78 {SELFPARAM();
79         float pushdeltatime;
80
81         if (self.active != ACTIVE_ACTIVE)
82                 return;
83
84         if (!isPushable(other))
85                 return;
86
87         EXACTTRIGGER_TOUCH;
88
89         pushdeltatime = time - other.lastpushtime;
90         if (pushdeltatime > 0.15) pushdeltatime = 0;
91         other.lastpushtime = time;
92         if(!pushdeltatime) return;
93
94         // div0: ticrate independent, 1 = identity (not 20)
95 #ifdef SVQC
96         other.velocity = other.velocity * pow(self.strength, pushdeltatime);
97
98         UpdateCSQCProjectile(other);
99 #elif defined(CSQC)
100         other.move_velocity = other.move_velocity * pow(self.strength, pushdeltatime);
101 #endif
102 }
103
104 // Spherical (gravity/repulsor) mode
105 void trigger_impulse_touch3()
106 {SELFPARAM();
107         float pushdeltatime;
108         float str;
109
110         if (self.active != ACTIVE_ACTIVE)
111                 return;
112
113         if (!isPushable(other))
114                 return;
115
116         EXACTTRIGGER_TOUCH;
117
118         pushdeltatime = time - other.lastpushtime;
119         if (pushdeltatime > 0.15) pushdeltatime = 0;
120         other.lastpushtime = time;
121         if(!pushdeltatime) return;
122
123         setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
124
125 #ifdef SVQC
126         str = min(self.radius, vlen(self.origin - other.origin));
127 #elif defined(CSQC)
128         str = min(self.radius, vlen(self.origin - other.move_origin));
129 #endif
130
131         if(self.falloff == 1)
132                 str = (1 - str / self.radius) * self.strength; // 1 in the inside
133         else if(self.falloff == 2)
134                 str = (str / self.radius) * self.strength; // 0 in the inside
135         else
136                 str = self.strength;
137
138 #ifdef SVQC
139         other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
140
141         UpdateCSQCProjectile(other);
142 #elif defined(CSQC)
143         other.move_velocity = other.move_velocity + normalize(other.move_origin - self.origin) * str * pushdeltatime;
144 #endif
145 }
146
147 REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_IMPULSE)
148
149 /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
150 -------- KEYS --------
151 target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
152                  If not, this trigger acts like a damper/accelerator field.
153
154 strength : This is how mutch force to add in the direction of .target each second
155                    when .target is set. If not, this is hoe mutch to slow down/accelerate
156                    someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
157
158 radius   : If set, act as a spherical device rather then a liniar one.
159
160 falloff : 0 = none, 1 = liniar, 2 = inverted liniar
161
162 -------- NOTES --------
163 Use a brush textured with common/origin in the trigger entity to determine the origin of the force
164 in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
165 */
166 #ifdef SVQC
167 bool trigger_impulse_send(entity this, entity to, int sf)
168 {
169         WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
170
171         WriteInt24_t(MSG_ENTITY, this.spawnflags);
172         WriteCoord(MSG_ENTITY, this.radius);
173         WriteCoord(MSG_ENTITY, this.strength);
174         WriteByte(MSG_ENTITY, this.falloff);
175         WriteByte(MSG_ENTITY, this.active);
176
177         trigger_common_write(this, true);
178
179         return true;
180 }
181
182 void trigger_impulse_link()
183 {
184     SELFPARAM();
185         trigger_link(self, trigger_impulse_send);
186 }
187
188 spawnfunc(trigger_impulse)
189 {
190         self.active = ACTIVE_ACTIVE;
191
192         trigger_init(self);
193
194         if(self.radius)
195         {
196                 if(!self.strength) self.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier;
197                 setorigin(self, self.origin);
198                 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
199                 self.touch = trigger_impulse_touch3;
200         }
201         else
202         {
203                 if(self.target)
204                 {
205                         if(!self.strength) self.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier;
206                         self.touch = trigger_impulse_touch1;
207                 }
208                 else
209                 {
210                         if(!self.strength) self.strength = 0.9;
211                         self.strength = pow(self.strength, autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
212                         self.touch = trigger_impulse_touch2;
213                 }
214         }
215
216         trigger_impulse_link();
217 }
218 #elif defined(CSQC)
219 NET_HANDLE(ENT_CLIENT_TRIGGER_IMPULSE, bool isnew)
220 {
221         self.spawnflags = ReadInt24_t();
222         self.radius = ReadCoord();
223         self.strength = ReadCoord();
224         self.falloff = ReadByte();
225         self.active = ReadByte();
226
227         trigger_common_read(true);
228         return = true;
229
230         self.classname = "trigger_impulse";
231         self.solid = SOLID_TRIGGER;
232         self.entremove = trigger_remove_generic;
233         //self.draw = trigger_draw_generic;
234         self.drawmask = MASK_NORMAL;
235         self.move_time = time;
236
237         if(self.radius) { self.move_touch = trigger_impulse_touch3; }
238         else if(self.target) { self.move_touch = trigger_impulse_touch1; }
239         else { self.move_touch = trigger_impulse_touch2; }
240 }
241 #endif