Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
speed.qc
Go to the documentation of this file.
1#include "speed.qh"
2
3// bones_was_here: TODO implement subscript support for vectors in gmqcc
4// or _something_ so code like this can be cheaper...
5#define ARRAY_AS_VECTOR(a) vec3((a)[0], (a)[1], (a)[2])
6#define VECTOR_TO_ARRAY(a, e) { vector v = (e); (a)[0] = v.x; (a)[1] = v.y; (a)[2] = v.z; }
8{
9 bool is_percentage = boolean(this.spawnflags & SPEED_PERCENTAGE);
10 bool is_add = boolean(this.spawnflags & SPEED_ADD);
11 bool is_launcher = boolean(this.spawnflags & SPEED_LAUNCHER);
12
13 bool is_positive[3];
14 is_positive[0] = boolean(this.spawnflags & SPEED_POSITIVE_X);
15 is_positive[1] = boolean(this.spawnflags & SPEED_POSITIVE_Y);
16 is_positive[2] = boolean(this.spawnflags & SPEED_POSITIVE_Z);
17
18 bool is_negative[3];
19 is_negative[0] = boolean(this.spawnflags & SPEED_NEGATIVE_X);
20 is_negative[1] = boolean(this.spawnflags & SPEED_NEGATIVE_Y);
21 is_negative[2] = boolean(this.spawnflags & SPEED_NEGATIVE_Z);
22
23 // speed cannot be negative except when subtracting
24 if(!is_add)
25 {
26 speed = max(speed, 0);
27 }
28
29 float pushvel[3];
30 VECTOR_TO_ARRAY(pushvel, pushed_entity.velocity)
31
32 for(int i = 0; i < 3; ++i)
33 {
34 // launcher can only be either positive or negative not both
35 if(is_launcher && is_positive[i] && is_negative[i])
36 {
37 is_positive[i] = is_negative[i] = false;
38 }
39
40 // ignore this direction
41 if(!is_positive[i] && !is_negative[i])
42 {
43 pushvel[i] = 0;
44 }
45 }
46
47 float oldspeed = vlen(ARRAY_AS_VECTOR(pushvel));
48
49 // the speed field is used to specify the percentage of the current speed
50 if(is_percentage)
51 {
52 speed = oldspeed * speed / 100;
53 }
54
55 float launcherspeed = 0;
56
57 // do this properly when not playing a Q3 map, do not put this in the loop
58 if(!STAT(Q3COMPAT, pushed_entity))
59 {
60 launcherspeed += speed;
61
62 // add the add speed in the same variable
63 // as it goes in the same direction
64 if(is_add) launcherspeed += oldspeed;
65 }
66
67 for(int i = 0; i < 3; ++i)
68 {
69 if(((pushvel[i] != 0) || is_launcher) && (is_positive[i] != is_negative[i]))
70 {
71 if(is_launcher)
72 {
73 // every direction weighs the same amount on launchers
74 // movedir does not matter
75 pushvel[i] = 1;
76
77 // this does not belong inside the loop
78 // only simulate this bug when playing a Q3 map
79 if(STAT(Q3COMPAT, pushed_entity))
80 {
81 launcherspeed += speed;
82
83 // add the add speed in the same variable
84 // as it goes in the same direction
85 if(is_add) launcherspeed += oldspeed;
86 }
87 }
88
89 if(is_positive[i])
90 {
91 pushvel[i] = copysign(pushvel[i], 1);
92 }
93 else if(is_negative[i])
94 {
95 pushvel[i] = copysign(pushvel[i], -1);
96 }
97 }
98 }
99
100 float oldvel[3];
101 VECTOR_TO_ARRAY(oldvel, pushed_entity.velocity)
102
103 if(is_launcher)
104 {
105 // launcher will always launch you in the correct direction
106 // even if speed is set to a negative value, fabs() is correct
107 VECTOR_TO_ARRAY(pushvel, normalize(ARRAY_AS_VECTOR(pushvel)) * fabs(launcherspeed))
108 }
109 else
110 {
111 if(!is_add)
112 VECTOR_TO_ARRAY(pushvel, normalize(ARRAY_AS_VECTOR(pushvel)) * speed)
113 else
114 VECTOR_TO_ARRAY(pushvel, normalize(ARRAY_AS_VECTOR(pushvel)) * speed + ARRAY_AS_VECTOR(oldvel))
115 }
116
117 for(int i = 0; i < 3; ++i)
118 {
119 // preserve unaffected directions
120 if(!is_positive[i] && !is_negative[i])
121 {
122 pushvel[i] = oldvel[i];
123 }
124 }
125
126 return ARRAY_AS_VECTOR(pushvel);
127}
128#undef ARRAY_AS_VECTOR
129#undef VECTOR_TO_ARRAY
130
131REGISTER_NET_LINKED(ENT_CLIENT_TARGET_SPEED)
132
134{
135 if(this.active != ACTIVE_ACTIVE)
136 return;
137
138 actor.velocity = target_speed_calculatevelocity(this, this.speed, actor);
139}
140
142{
143 this.active = ACTIVE_ACTIVE;
144}
145
146#ifdef SVQC
147void target_speed_link(entity this);
148
149/*
150 * ENTITY PARAMETERS:
151 *
152 * targetname: Activating trigger points to this.
153 * speed: Speed value to set (default: 100).
154 */
155spawnfunc(target_speed)
156{
157 this.active = ACTIVE_ACTIVE;
158 this.setactive = generic_netlinked_setactive;
159 this.use = target_speed_use;
160 this.reset = target_speed_reset;
161
162 // support a 0 speed setting AND a default
163 string s = GetField_fullspawndata(this, "speed", false);
164 if (!s || s == "")
165 this.speed = 100;
166
167 target_speed_link(this);
168}
169
170bool target_speed_send(entity this, entity to, float sf)
171{
172 WriteHeader(MSG_ENTITY, ENT_CLIENT_TARGET_SPEED);
173
178
179 return true;
180}
181
183{
184 Net_LinkEntity(this, false, 0, target_speed_send);
185}
186
187#elif defined(CSQC)
188
189void target_speed_remove(entity this)
190{
191 strfree(this.targetname);
192}
193
194NET_HANDLE(ENT_CLIENT_TARGET_SPEED, bool isnew)
195{
196 this.spawnflags = ReadShort();
197 this.active = ReadByte();
198 this.targetname = strzone(ReadString());
199 this.speed = ReadCoord();
200
201 this.use = target_speed_use;
202 this.entremove = target_speed_remove;
203
204 return true;
205}
206#endif
#define boolean(value)
Definition bool.qh:9
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define ReadString
int spawnflags
Definition ammo.qh:15
#define use
int active
Definition defs.qh:34
const int ACTIVE_ACTIVE
Definition defs.qh:37
float speed
Definition dynlight.qc:9
#define NET_HANDLE(id, param)
Definition net.qh:15
const int MSG_ENTITY
Definition net.qh:115
#define WriteHeader(to, id)
Definition net.qh:221
#define REGISTER_NET_LINKED(id)
Definition net.qh:55
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
Definition net.qh:123
int ReadByte()
#define STAT(...)
Definition stats.qh:82
#define VECTOR_TO_ARRAY(a, e)
Definition speed.qc:6
#define ARRAY_AS_VECTOR(a)
Definition speed.qc:5
vector target_speed_calculatevelocity(entity this, float speed, entity pushed_entity)
Definition speed.qc:7
void target_speed_use(entity this, entity actor, entity trigger)
Definition speed.qc:133
bool target_speed_send(entity this, entity to, float sf)
Definition speed.qc:170
void target_speed_link(entity this)
Definition speed.qc:182
void target_speed_reset(entity this)
Definition speed.qc:141
#define SPEED_NEGATIVE_X
Definition speed.qh:7
#define SPEED_POSITIVE_X
Definition speed.qh:6
#define SPEED_POSITIVE_Z
Definition speed.qh:10
#define SPEED_NEGATIVE_Z
Definition speed.qh:11
#define SPEED_PERCENTAGE
Definition speed.qh:4
#define SPEED_NEGATIVE_Y
Definition speed.qh:9
#define SPEED_POSITIVE_Y
Definition speed.qh:8
#define SPEED_ADD
Definition speed.qh:5
#define SPEED_LAUNCHER
Definition speed.qh:12
float copysign(float e, float f)
Definition mathlib.qc:225
void WriteString(string data, float dest, float desto)
float vlen(vector v)
void WriteShort(float data, float dest, float desto)
void WriteCoord(float data, float dest, float desto)
vector normalize(vector v)
void WriteByte(float data, float dest, float desto)
float fabs(float f)
string strzone(string s)
float max(float f,...)
vector
Definition self.qh:92
entity this
Definition self.qh:72
void
Definition self.qh:72
string GetField_fullspawndata(entity e, string fieldname, bool vfspath)
Retrieves the value of a map entity field from fullspawndata.
Definition main.qc:451
#define spawnfunc(id)
Definition spawnfunc.qh:96
#define strfree(this)
Definition string.qh:59
void generic_netlinked_setactive(entity this, int act)
Definition triggers.qc:65
string targetname
Definition triggers.qh:56