Xonotic
impulse.qc
Go to the documentation of this file.
1 #include "impulse.qh"
2 // targeted (directional) mode
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 
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
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
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  {
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.solid = SOLID_TRIGGER;
226  this.entremove = trigger_remove_generic;
227  this.move_time = time;
228 
229  if (this.radius)
230  {
231  settouch(this, trigger_impulse_touch_radial);
232  }
233  else if (this.target)
234  {
235  settouch(this, trigger_impulse_touch_directional);
236  }
237  else
238  {
239  settouch(this, trigger_impulse_touch_accel);
240  }
241 }
242 #endif
const int IMPULSE_DIRECTIONAL_SPEEDTARGET
Definition: impulse.qh:20
const float IMPULSE_DEFAULT_ACCEL_STRENGTH
Definition: impulse.qh:24
#define REGISTER_NET_LINKED(id)
Definition: net.qh:67
int falloff
Definition: impulse.qh:12
float strength
Definition: impulse.qh:13
#define EXACTTRIGGER_TOUCH(e, t)
Definition: common.qh:116
entity() spawn
float radius
Definition: impulse.qh:11
const int FALLOFF_LINEAR
Definition: impulse.qh:17
#define NET_HANDLE(id, param)
Definition: net.qh:12
entity to
Definition: self.qh:96
spawnfunc(info_player_attacker)
Definition: sv_assault.qc:283
origin
Definition: ent_cs.qc:114
void trigger_impulse_touch_accel(entity this, entity toucher)
Definition: impulse.qc:59
#define UNSET_ONGROUND(s)
Definition: movetypes.qh:18
float spawnflags
Definition: progsdefs.qc:191
void trigger_impulse_touch_radial(entity this, entity toucher)
Definition: impulse.qc:91
void UpdateCSQCProjectile(entity e)
const int ACTIVE_ACTIVE
Definition: defs.qh:37
#define NULL
Definition: post.qh:17
const float IMPULSE_DIRECTIONAL_MAX_ACCEL_FACTOR
Definition: impulse.qh:28
float move_time
Definition: movetypes.qh:77
const float IMPULSE_DEFAULT_DIRECTIONAL_STRENGTH
Definition: impulse.qh:23
const float SOLID_TRIGGER
Definition: csprogsdefs.qc:245
void trigger_impulse_touch_directional(entity this, entity toucher)
Definition: impulse.qc:3
string targetname
Definition: progsdefs.qc:194
int active
Definition: defs.qh:34
const float IMPULSE_MAX_PUSHDELTATIME
Definition: impulse.qh:26
setorigin(ent, v)
string target
Definition: progsdefs.qc:193
float time
Definition: csprogsdefs.qc:16
bool isPushable(entity e)
Definition: triggers.qc:3
const int FALLOFF_LINEAR_INV
Definition: impulse.qh:18
const float IMPULSE_DEFAULT_RADIAL_STRENGTH
Definition: impulse.qh:22
float solid
Definition: csprogsdefs.qc:99