]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/trigger/impulse.qc
Network impulse triggers
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / trigger / impulse.qc
1 // targeted (directional) mode
2 void trigger_impulse_touch1()
3 {
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         str = min(self.radius, vlen(self.origin - other.origin));
25
26         if(self.falloff == 1)
27                 str = (str / self.radius) * self.strength;
28         else if(self.falloff == 2)
29                 str = (1 - (str / self.radius)) * self.strength;
30         else
31                 str = self.strength;
32
33         pushdeltatime = time - other.lastpushtime;
34         if (pushdeltatime > 0.15) pushdeltatime = 0;
35         other.lastpushtime = time;
36         if(!pushdeltatime) return;
37
38 #ifdef CSQC
39         print("Touchie!\n");
40 #endif
41
42         other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime;
43         other.flags &= ~FL_ONGROUND;
44 #ifdef SVQC
45         UpdateCSQCProjectile(other);
46 #endif
47 }
48
49 // Directionless (accelerator/decelerator) mode
50 void trigger_impulse_touch2()
51 {
52         float pushdeltatime;
53
54         if (self.active != ACTIVE_ACTIVE)
55                 return;
56
57         if (!isPushable(other))
58                 return;
59
60         EXACTTRIGGER_TOUCH;
61
62         pushdeltatime = time - other.lastpushtime;
63         if (pushdeltatime > 0.15) pushdeltatime = 0;
64         other.lastpushtime = time;
65         if(!pushdeltatime) return;
66
67         // div0: ticrate independent, 1 = identity (not 20)
68         other.velocity = other.velocity * pow(self.strength, pushdeltatime);
69 #ifdef SVQC
70         UpdateCSQCProjectile(other);
71 #endif
72 }
73
74 // Spherical (gravity/repulsor) mode
75 void trigger_impulse_touch3()
76 {
77         float pushdeltatime;
78         float str;
79
80         if (self.active != ACTIVE_ACTIVE)
81                 return;
82
83         if (!isPushable(other))
84                 return;
85
86         EXACTTRIGGER_TOUCH;
87
88         pushdeltatime = time - other.lastpushtime;
89         if (pushdeltatime > 0.15) pushdeltatime = 0;
90         other.lastpushtime = time;
91         if(!pushdeltatime) return;
92
93         setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
94
95         str = min(self.radius, vlen(self.origin - other.origin));
96
97         if(self.falloff == 1)
98                 str = (1 - str / self.radius) * self.strength; // 1 in the inside
99         else if(self.falloff == 2)
100                 str = (str / self.radius) * self.strength; // 0 in the inside
101         else
102                 str = self.strength;
103
104         other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
105 #ifdef SVQC
106         UpdateCSQCProjectile(other);
107 #endif
108 }
109
110 /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
111 -------- KEYS --------
112 target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
113                  If not, this trigger acts like a damper/accelerator field.
114
115 strength : This is how mutch force to add in the direction of .target each second
116                    when .target is set. If not, this is hoe mutch to slow down/accelerate
117                    someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
118
119 radius   : If set, act as a spherical device rather then a liniar one.
120
121 falloff : 0 = none, 1 = liniar, 2 = inverted liniar
122
123 -------- NOTES --------
124 Use a brush textured with common/origin in the trigger entity to determine the origin of the force
125 in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
126 */
127 #ifdef SVQC
128 bool trigger_impulse_send(entity to, int sf)
129 {
130         WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
131
132         WriteCoord(MSG_ENTITY, self.radius);
133         WriteCoord(MSG_ENTITY, self.strength);
134         WriteByte(MSG_ENTITY, self.falloff);
135         WriteByte(MSG_ENTITY, self.active);
136
137         trigger_common_write(true);
138
139         return true;
140 }
141
142 void trigger_impulse_link()
143 {
144         Net_LinkEntity(self, 0, false, trigger_impulse_send);
145 }
146
147 void spawnfunc_trigger_impulse()
148 {
149         self.active = ACTIVE_ACTIVE;
150
151         EXACTTRIGGER_INIT;
152         if(self.radius)
153         {
154                 if(!self.strength) self.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier;
155                 setorigin(self, self.origin);
156                 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
157                 self.touch = trigger_impulse_touch3;
158         }
159         else
160         {
161                 if(self.target)
162                 {
163                         if(!self.strength) self.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier;
164                         self.touch = trigger_impulse_touch1;
165                 }
166                 else
167                 {
168                         if(!self.strength) self.strength = 0.9;
169                         self.strength = pow(self.strength, autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
170                         self.touch = trigger_impulse_touch2;
171                 }
172         }
173
174         trigger_impulse_link();
175 }
176 #elif defined(CSQC)
177 void ent_trigger_impulse()
178 {
179         self.radius = ReadCoord();
180         self.strength = ReadCoord();
181         self.falloff = ReadByte();
182         self.active = ReadByte();
183
184         trigger_common_read(true);
185
186
187         self.classname = "trigger_impulse";
188         self.solid = SOLID_TRIGGER;
189         self.entremove = trigger_remove_generic;
190         self.draw = trigger_draw_generic;
191         self.drawmask = MASK_NORMAL;
192         self.move_time = time;
193
194         if(self.radius) { self.trigger_touch = trigger_impulse_touch3; }
195         else if(self.target) { self.trigger_touch = trigger_impulse_touch1; }
196         else { self.trigger_touch = trigger_impulse_touch2; }
197 }
198 #endif