Xonotic
train.qc
Go to the documentation of this file.
1 #include "train.qh"
3 .entity future_target;
4 void train_next(entity this);
5 #ifdef SVQC
6 void train_use(entity this, entity actor, entity trigger);
7 #endif
8 void train_wait(entity this)
9 {
10  SUB_UseTargets(this.enemy, NULL, NULL);
11  this.enemy = NULL;
12 
13  // if turning is enabled, the train will turn toward the next point while waiting
14  if(this.platmovetype_turn && !this.train_wait_turning)
15  {
16  entity targ, cp;
17  vector ang;
18  targ = this.future_target;
19  if((this.spawnflags & TRAIN_CURVE) && targ.curvetarget)
20  cp = find(NULL, targetname, targ.curvetarget);
21  else
22  cp = NULL;
23 
24  if(cp) // bezier curves movement
25  ang = cp.origin - (this.origin - this.view_ofs); // use the origin of the control point of the next path_corner
26  else // linear movement
27  ang = targ.origin - (this.origin - this.view_ofs); // use the origin of the next path_corner
28  ang = vectoangles(ang);
29  ang_x = -ang_x; // flip up / down orientation
30 
31  if(this.wait > 0) // slow turning
32  SUB_CalcAngleMove(this, ang, TSPEED_TIME, this.ltime - time + this.wait, train_wait);
33  else // instant turning
34  SUB_CalcAngleMove(this, ang, TSPEED_TIME, 0.0000001, train_wait);
35  this.train_wait_turning = true;
36  return;
37  }
38 
39 #ifdef SVQC
40  if(this.noise != "")
41  stopsoundto(MSG_BROADCAST, this, CH_TRIGGER_SINGLE); // send this as unreliable only, as the train will resume operation shortly anyway
42 #endif
43 
44 #ifdef SVQC
45  entity tg = this.future_target;
46  if(tg.spawnflags & TRAIN_NEEDACTIVATION)
47  {
48  this.use = train_use;
49  setthink(this, func_null);
50  this.nextthink = 0;
51  }
52  else
53 #endif
54  if(this.wait < 0 || this.train_wait_turning) // no waiting or we already waited while turning
55  {
56  this.train_wait_turning = false;
57  train_next(this);
58  }
59  else
60  {
61  setthink(this, train_next);
62  this.nextthink = this.ltime + this.wait;
63  }
64 }
65 
67 {
68  if(this.target_random)
69  {
71  for(entity t = NULL; (t = find(t, targetname, this.target));)
72  {
73  RandomSelection_AddEnt(t, 1, 0);
74  }
76  }
77  else
78  {
79  return find(NULL, targetname, this.target);
80  }
81 }
82 
83 void train_next(entity this)
84 {
85  entity targ = NULL, cp = NULL;
86  vector cp_org = '0 0 0';
87 
88  targ = this.future_target;
89 
90  this.target = targ.target;
91  this.target_random = targ.target_random;
92  this.future_target = train_next_find(targ);
93 
94  if (this.spawnflags & TRAIN_CURVE)
95  {
96  if(targ.curvetarget)
97  {
98  cp = find(NULL, targetname, targ.curvetarget); // get its second target (the control point)
99  cp_org = cp.origin - this.view_ofs; // no control point found, assume a straight line to the destination
100  }
101  }
102  if (this.target == "")
103  objerror(this, "train_next: no next target");
104  this.wait = targ.wait;
105  if (!this.wait)
106  this.wait = 0.1;
107 
108  if(targ.platmovetype)
109  {
110  // this path_corner contains a movetype overrider, apply it
111  this.platmovetype_start = targ.platmovetype_start;
112  this.platmovetype_end = targ.platmovetype_end;
113  }
114  else
115  {
116  // this path_corner doesn't contain a movetype overrider, use the train's defaults
119  }
120 
121  if (targ.speed)
122  {
123  if (cp)
124  SUB_CalcMove_Bezier(this, cp_org, targ.origin - this.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
125  else
126  SUB_CalcMove(this, targ.origin - this.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
127  }
128  else
129  {
130  if (cp)
131  SUB_CalcMove_Bezier(this, cp_org, targ.origin - this.view_ofs, TSPEED_LINEAR, this.speed, train_wait);
132  else
133  SUB_CalcMove(this, targ.origin - this.view_ofs, TSPEED_LINEAR, this.speed, train_wait);
134  }
135 
136  if(this.noise != "")
138 }
139 
140 REGISTER_NET_LINKED(ENT_CLIENT_TRAIN)
141 
142 #ifdef SVQC
143 float train_send(entity this, entity to, float sf)
144 {
145  WriteHeader(MSG_ENTITY, ENT_CLIENT_TRAIN);
146  WriteByte(MSG_ENTITY, sf);
147 
148  if(sf & SF_TRIGGER_INIT)
149  {
150  WriteString(MSG_ENTITY, this.platmovetype);
151  WriteByte(MSG_ENTITY, this.platmovetype_turn);
152  WriteByte(MSG_ENTITY, this.spawnflags);
153 
154  WriteString(MSG_ENTITY, this.model);
155 
156  trigger_common_write(this, true);
157 
158  WriteString(MSG_ENTITY, this.curvetarget);
159 
160  WriteVector(MSG_ENTITY, this.pos1);
161  WriteVector(MSG_ENTITY, this.pos2);
162 
163  WriteVector(MSG_ENTITY, this.size);
164 
165  WriteVector(MSG_ENTITY, this.view_ofs);
166 
167  WriteAngleVector(MSG_ENTITY, this.mangle);
168 
169  WriteShort(MSG_ENTITY, this.speed);
170  WriteShort(MSG_ENTITY, this.height);
171  WriteByte(MSG_ENTITY, this.lip);
172  WriteByte(MSG_ENTITY, this.state);
173  WriteByte(MSG_ENTITY, this.wait);
174 
175  WriteShort(MSG_ENTITY, this.dmg);
176  WriteByte(MSG_ENTITY, this.dmgtime);
177  }
178 
179  if(sf & SF_TRIGGER_RESET)
180  {
181  // used on client
182  }
183 
184  return true;
185 }
186 
187 void train_link(entity this)
188 {
189  //Net_LinkEntity(this, 0, false, train_send);
190 }
191 
192 void train_use(entity this, entity actor, entity trigger)
193 {
194  this.nextthink = this.ltime + 1;
195  setthink(this, train_next);
196  this.use = func_null; // not again, next target can set it again if needed
197  if(trigger.target2 && trigger.target2 != "")
198  this.future_target = find(NULL, targetname, trigger.target2);
199 }
200 
201 void func_train_find(entity this)
202 {
203  entity targ = train_next_find(this);
204  this.target = targ.target;
205  this.target_random = targ.target_random;
206  // save the future target for later
207  this.future_target = train_next_find(targ);
208  if (this.target == "")
209  objerror(this, "func_train_find: no next target");
210  setorigin(this, targ.origin - this.view_ofs);
211 
212  if(!(this.spawnflags & TRAIN_NEEDACTIVATION))
213  {
214  this.nextthink = this.ltime + 1;
215  setthink(this, train_next);
216  }
217 
218  train_link(this);
219 }
220 
221 #endif
222 
223 /*QUAKED spawnfunc_func_train (0 .5 .8) ?
224 Ridable platform, targets spawnfunc_path_corner path to follow.
225 speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
226 target : targetname of first spawnfunc_path_corner (starts here)
227 */
228 #ifdef SVQC
229 spawnfunc(func_train)
230 {
231  if (this.noise != "")
232  precache_sound(this.noise);
233 
234  if (this.target == "")
235  objerror(this, "func_train without a target");
236  if (!this.speed)
237  this.speed = 100;
238 
239  if (!InitMovingBrushTrigger(this))
240  return;
241  this.effects |= EF_LOWPRECISION;
242 
244  this.use = train_use;
245 
246  if (this.spawnflags & TRAIN_TURN)
247  {
248  this.platmovetype_turn = true;
249  this.view_ofs = '0 0 0'; // don't offset a rotating train, origin works differently now
250  }
251  else
252  this.view_ofs = this.mins;
253 
254  // wait for targets to spawn
255  InitializeEntity(this, func_train_find, INITPRIO_FINDTARGET);
256 
257  setblocked(this, generic_plat_blocked);
258  if(this.dmg && (this.message == ""))
259  this.message = " was squished";
260  if(this.dmg && (this.message2 == ""))
261  this.message2 = "was squished by";
262  if(this.dmg && (!this.dmgtime))
263  this.dmgtime = 0.25;
264  this.dmgtime2 = time;
265 
266  if(!set_platmovetype(this, this.platmovetype))
267  return;
270 
271  // TODO make a reset function for this one
272 }
273 #elif defined(CSQC)
274 void train_draw(entity this)
275 {
276  //Movetype_Physics_NoMatchServer();
278 }
279 
280 NET_HANDLE(ENT_CLIENT_TRAIN, bool isnew)
281 {
282  float sf = ReadByte();
283 
284  if(sf & SF_TRIGGER_INIT)
285  {
286  this.platmovetype = strzone(ReadString());
287  this.platmovetype_turn = ReadByte();
288  this.spawnflags = ReadByte();
289 
290  this.model = strzone(ReadString());
291  _setmodel(this, this.model);
292 
293  trigger_common_read(this, true);
294 
295  this.curvetarget = strzone(ReadString());
296 
297  this.pos1 = ReadVector();
298  this.pos2 = ReadVector();
299 
300  this.size = ReadVector();
301 
302  this.view_ofs = ReadVector();
303 
304  this.mangle = ReadAngleVector();
305 
306  this.speed = ReadShort();
307  this.height = ReadShort();
308  this.lip = ReadByte();
309  this.state = ReadByte();
310  this.wait = ReadByte();
311 
312  this.dmg = ReadShort();
313  this.dmgtime = ReadByte();
314 
315  this.classname = "func_train";
316  this.solid = SOLID_BSP;
318  this.drawmask = MASK_NORMAL;
319  this.draw = train_draw;
320  if (isnew) IL_PUSH(g_drawables, this);
321  this.entremove = trigger_remove_generic;
322 
323  if(set_platmovetype(this, this.platmovetype))
324  {
327  }
328 
329  // everything is set up by the time the train is linked, we shouldn't need this
330  //func_train_find();
331 
332  // but we will need these
333  train_next(this);
334 
336  this.move_time = time;
337  }
338 
339  if(sf & SF_TRIGGER_RESET)
340  {
341  // TODO: make a reset function for trains
342  }
343 
344  return true;
345 }
346 
347 #endif
float state
Definition: subs.qh:32
const int TRAIN_CURVE
Definition: train.qh:4
float target_random
Definition: subs.qh:57
#define REGISTER_NET_LINKED(id)
Definition: net.qh:67
entity future_target
Definition: train.qc:3
float speed
Definition: subs.qh:41
vector view_ofs
Definition: progsdefs.qc:151
const int SF_TRIGGER_INIT
Definition: defs.qh:22
bool autocvar_cl_projectiles_sloppy
Definition: projectile.qh:5
string noise
Definition: progsdefs.qc:209
#define ReadString
float platmovetype_end
Definition: subs.qh:44
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
void train_next(entity this)
Definition: train.qc:83
entity train_next_find(entity this)
Definition: train.qc:66
entity() spawn
const int TSPEED_LINEAR
Definition: subs.qh:71
bool set_platmovetype(entity e, string s)
Definition: platforms.qc:201
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition: triggers.qc:366
#define NET_HANDLE(id, param)
Definition: net.qh:12
float train_wait_turning
Definition: train.qc:2
float dmg
Definition: platforms.qh:6
entity to
Definition: self.qh:96
float platmovetype_end_default
Definition: platforms.qc:200
spawnfunc(info_player_attacker)
Definition: sv_assault.qc:283
origin
Definition: ent_cs.qc:114
string platmovetype
Definition: subs.qh:43
string classname
Definition: csprogsdefs.qc:107
vector size
Definition: csprogsdefs.qc:114
float ltime
Definition: progsdefs.qc:107
float effects
Definition: csprogsdefs.qc:111
void SUB_CalcMove(entity this, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
Definition: subs.qc:256
float spawnflags
Definition: progsdefs.qc:191
float platmovetype_turn
Definition: subs.qc:105
string model
Definition: csprogsdefs.qc:108
const int TRAIN_NEEDACTIVATION
Definition: train.qh:6
#define RandomSelection_AddEnt(e, weight, priority)
Definition: random.qh:14
entity enemy
Definition: sv_ctf.qh:143
vector mins
Definition: csprogsdefs.qc:113
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
string curvetarget
Definition: subs.qh:56
void Movetype_Physics_MatchServer(entity this, bool sloppy)
Definition: movetypes.qc:851
float platmovetype_start_default
Definition: platforms.qc:200
float height
Definition: jumppads.qh:12
entity RandomSelection_chosen_ent
Definition: random.qh:5
float MOVETYPE_PUSH
Definition: progsdefs.qc:253
float wait
Definition: subs.qh:39
const int SF_TRIGGER_RESET
Definition: defs.qh:24
const int TSPEED_TIME
Definition: subs.qh:70
string message
Definition: powerups.qc:19
#define NULL
Definition: post.qh:17
float platmovetype_start
Definition: subs.qh:44
const float VOL_BASE
Definition: sound.qh:36
const float MASK_NORMAL
Definition: csprogsdefs.qc:164
float drawmask
Definition: csprogsdefs.qc:95
float nextthink
Definition: csprogsdefs.qc:121
const int CH_TRIGGER_SINGLE
Definition: sound.qh:13
vector(float skel, float bonenum) _skel_get_boneabs_hidden
void train_wait(entity this)
Definition: train.qc:8
float dmgtime
Definition: platforms.qh:7
const float SOLID_BSP
Definition: csprogsdefs.qc:248
void InitializeEntity(entity e, void(entity this) func, int order)
Definition: world.qc:2146
float move_time
Definition: movetypes.qh:77
float lip
Definition: subs.qh:40
#define _sound(e, c, s, v, a)
Definition: sound.qh:50
const int TRAIN_TURN
Definition: train.qh:5
string targetname
Definition: progsdefs.qc:194
float dmgtime2
Definition: platforms.qh:8
void generic_plat_blocked(entity this, entity blocker)
Definition: platforms.qc:3
vector pos1
Definition: subs.qh:50
vector mangle
Definition: subs.qh:51
setorigin(ent, v)
#define setthink(e, f)
void SUB_CalcAngleMove(entity this, vector destangle, float tspeedtype, float tspeed, void(entity this) func)
Definition: subs.qc:331
#define use
Definition: csprogsdefs.qh:50
string target
Definition: progsdefs.qc:193
float time
Definition: csprogsdefs.qc:16
vector pos2
Definition: subs.qh:50
void SUB_CalcMove_Bezier(entity this, vector tcontrol, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
Definition: subs.qc:194
IntrusiveList g_drawables
Definition: main.qh:77
void set_movetype(entity this, int mt)
float EF_LOWPRECISION
var void func_null()
const float ATTEN_IDLE
Definition: sound.qh:32
float solid
Definition: csprogsdefs.qc:99