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