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