]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/trigger/impulse.qc
Merge branch 'master' into Mario/killsound
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / trigger / impulse.qc
1 #include "impulse.qh"
2 // targeted (directional) mode
3 void trigger_impulse_touch1(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         str = min(this.radius, vlen(this.origin - toucher.origin));
26
27         if(this.falloff == 1)
28                 str = (str / this.radius) * this.strength;
29         else if(this.falloff == 2)
30                 str = (1 - (str / this.radius)) * this.strength;
31         else
32                 str = this.strength;
33
34         pushdeltatime = time - toucher.lastpushtime;
35         if (pushdeltatime > 0.15) pushdeltatime = 0;
36         toucher.lastpushtime = time;
37         if(!pushdeltatime) return;
38
39         if(this.spawnflags & 64)
40         {
41                 float addspeed = str - toucher.velocity * normalize(targ.origin - this.origin);
42                 if (addspeed > 0)
43                 {
44                         float accelspeed = min(8 * 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_touch2(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 > 0.15) pushdeltatime = 0;
73         toucher.lastpushtime = time;
74         if(!pushdeltatime) return;
75
76         // div0: ticrate independent, 1 = identity (not 20)
77         toucher.velocity = toucher.velocity * (this.strength ** pushdeltatime);
78
79 #ifdef SVQC
80         UpdateCSQCProjectile(toucher);
81 #endif
82 }
83
84 // Spherical (gravity/repulsor) mode
85 void trigger_impulse_touch3(entity this, entity toucher)
86 {
87         float pushdeltatime;
88         float str;
89
90         if (this.active != ACTIVE_ACTIVE)
91                 return;
92
93         if (!isPushable(toucher))
94                 return;
95
96         EXACTTRIGGER_TOUCH(this, toucher);
97
98         pushdeltatime = time - toucher.lastpushtime;
99         if (pushdeltatime > 0.15) pushdeltatime = 0;
100         toucher.lastpushtime = time;
101         if(!pushdeltatime) return;
102
103         setsize(this, '-1 -1 -1' * this.radius,'1 1 1' * this.radius);
104
105         str = min(this.radius, vlen(this.origin - toucher.origin));
106
107         if(this.falloff == 1)
108                 str = (1 - str / this.radius) * this.strength; // 1 in the inside
109         else if(this.falloff == 2)
110                 str = (str / this.radius) * this.strength; // 0 in the inside
111         else
112                 str = this.strength;
113
114         toucher.velocity = toucher.velocity + normalize(toucher.origin - this.origin) * str * pushdeltatime;
115
116 #ifdef SVQC
117         UpdateCSQCProjectile(toucher);
118 #endif
119 }
120
121 REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_IMPULSE)
122
123 /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
124 -------- KEYS --------
125 target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
126                  If not, this trigger acts like a damper/accelerator field.
127
128 strength : This is how mutch force to add in the direction of .target each second
129                    when .target is set. If not, this is hoe mutch to slow down/accelerate
130                    someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
131
132 radius   : If set, act as a spherical device rather then a liniar one.
133
134 falloff : 0 = none, 1 = liniar, 2 = inverted liniar
135
136 -------- NOTES --------
137 Use a brush textured with common/origin in the trigger entity to determine the origin of the force
138 in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
139 */
140 #ifdef SVQC
141 bool trigger_impulse_send(entity this, entity to, int sf)
142 {
143         WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
144
145         WriteInt24_t(MSG_ENTITY, this.spawnflags);
146         WriteCoord(MSG_ENTITY, this.radius);
147         WriteCoord(MSG_ENTITY, this.strength);
148         WriteByte(MSG_ENTITY, this.falloff);
149         WriteByte(MSG_ENTITY, this.active);
150
151         trigger_common_write(this, true);
152
153         return true;
154 }
155
156 void trigger_impulse_link(entity this)
157 {
158         trigger_link(this, trigger_impulse_send);
159 }
160
161 spawnfunc(trigger_impulse)
162 {
163         this.active = ACTIVE_ACTIVE;
164
165         trigger_init(this);
166
167         if(this.radius)
168         {
169                 if(!this.strength) this.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier;
170                 setorigin(this, this.origin);
171                 setsize(this, '-1 -1 -1' * this.radius,'1 1 1' * this.radius);
172                 settouch(this, trigger_impulse_touch3);
173         }
174         else
175         {
176                 if(this.target)
177                 {
178                         if(!this.strength) this.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier;
179                         settouch(this, trigger_impulse_touch1);
180                 }
181                 else
182                 {
183                         if(!this.strength) this.strength = 0.9;
184                         this.strength = (this.strength ** autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
185                         settouch(this, trigger_impulse_touch2);
186                 }
187         }
188
189         trigger_impulse_link(this);
190 }
191 #elif defined(CSQC)
192 NET_HANDLE(ENT_CLIENT_TRIGGER_IMPULSE, bool isnew)
193 {
194         this.spawnflags = ReadInt24_t();
195         this.radius = ReadCoord();
196         this.strength = ReadCoord();
197         this.falloff = ReadByte();
198         this.active = ReadByte();
199
200         trigger_common_read(this, true);
201         return = true;
202
203         this.classname = "trigger_impulse";
204         this.solid = SOLID_TRIGGER;
205         this.entremove = trigger_remove_generic;
206         this.move_time = time;
207
208         if (this.radius) { settouch(this, trigger_impulse_touch3); }
209         else if (this.target) { settouch(this, trigger_impulse_touch1); }
210         else { settouch(this, trigger_impulse_touch2); }
211 }
212 #endif