Xonotic
ladder.qc
Go to the documentation of this file.
1 #include "ladder.qh"
2 REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
3 
5 {
6 #ifdef CSQC
7  // TODO: check if this is what is causing the glitchiness when switching between them
8  float dt = time - this.move_time;
9  this.move_time = time;
10  if(dt <= 0) { return; }
11 #endif
12 
13  // set myself as current ladders where possible
14  IL_EACH(g_ladderents, it.ladder_entity == this,
15  {
16  it.ladder_entity = NULL;
17  IL_REMOVE(g_ladderents, it);
18  });
19 
20  FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, !it.ladder_entity && IS_PLAYER(it) && it.move_movetype != MOVETYPE_NOCLIP && !IS_DEAD(it),
21  {
22  vector emin = it.absmin;
23  vector emax = it.absmax;
24  if(this.solid == SOLID_BSP || (IS_CSQC && this.solid == SOLID_TRIGGER)) // CSQC doesn't expand properly
25  {
26  emin -= '1 1 1';
27  emax += '1 1 1';
28  }
29  if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
30  {
31  if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
32  {
33  if(!it.ladder_entity)
34  IL_PUSH(g_ladderents, it);
35  it.ladder_entity = this;
36  }
37  }
38  });
39 
40 #ifdef SVQC
41  this.nextthink = time;
42 #endif
43 }
44 
45 #ifdef SVQC
46 bool func_ladder_send(entity this, entity to, int sf)
47 {
48  WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
49 
50  WriteString(MSG_ENTITY, this.classname);
51  WriteByte(MSG_ENTITY, this.skin);
52  WriteCoord(MSG_ENTITY, this.speed);
53 
54  trigger_common_write(this, false);
55 
56  return true;
57 }
58 
59 void func_ladder_link(entity this)
60 {
61  trigger_link(this, func_ladder_send);
62  //this.model = "null";
63 }
64 
65 void func_ladder_init(entity this)
66 {
67  trigger_init(this);
68  func_ladder_link(this);
70  this.nextthink = time;
71 
72  if(min(this.absmax.x - this.absmin.x, this.absmax.y - this.absmin.y) > 100)
73  return;
74 
75  entity tracetest_ent = spawn();
76  setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
77  tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
78 
79  vector top_min = (this.absmin + this.absmax) / 2;
80  top_min.z = this.absmax.z;
81  vector top_max = top_min;
82  top_max.z += PL_MAX_CONST.z - PL_MIN_CONST.z;
83  tracebox(top_max + jumpstepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
85  {
86  tracebox(top_max + stepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
88  {
89  tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
91  {
92  if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
93  && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
94  {
95  // move top on one side
96  top_max.y = top_min.y = this.absmin.y + (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
97  }
98  else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
99  && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
100  {
101  // move top on one side
102  top_max.x = top_min.x = this.absmin.x + (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
103  }
104  tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
105  if(trace_startsolid)
106  {
107  if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
108  && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
109  {
110  // alternatively on the other side
111  top_max.y = top_min.y = this.absmax.y - (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
112  }
113  else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
114  && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
115  {
116  // alternatively on the other side
117  top_max.x = top_min.x = this.absmax.x - (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
118  }
119  tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
120  }
121  }
122  }
123  }
124  delete(tracetest_ent);
125  if(trace_startsolid || trace_endpos.z < this.absmax.z)
126  {
127  return;
128  }
129 
130  this.bot_pickup = true; // allow bots to make use of this ladder
131  float cost = waypoint_getlinearcost(trace_endpos.z - this.absmin.z);
132  top_min = trace_endpos;
133  waypoint_spawnforteleporter_boxes(this, WAYPOINTFLAG_LADDER, this.absmin, this.absmax, top_min, top_min, cost);
134 }
135 
136 spawnfunc(func_ladder)
137 {
138  IL_PUSH(g_ladders, this); // TODO: also func_water? bots currently loop through func_ladder only
139 
140  func_ladder_init(this);
141 }
142 
143 spawnfunc(func_water)
144 {
145  func_ladder_init(this);
146 }
147 
148 #elif defined(CSQC)
149 .float speed;
150 
151 void func_ladder_draw(entity this) { func_ladder_think(this); }
152 
153 void func_ladder_remove(entity this)
154 {
155  IL_EACH(g_ladderents, it.ladder_entity == this,
156  {
157  it.ladder_entity = NULL;
158  IL_REMOVE(g_ladderents, it);
159  });
160  strfree(this.classname);
161 }
162 
163 NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
164 {
165  this.classname = strzone(ReadString());
166  this.skin = ReadByte();
167  this.speed = ReadCoord();
168  this.solid = SOLID_TRIGGER;
169 
170  trigger_common_read(this, false);
171 
172  if(isnew)
173  IL_PUSH(g_drawables, this);
174  this.draw = func_ladder_draw;
175  this.drawmask = MASK_NORMAL;
176 
177  this.move_time = time;
178  this.entremove = func_ladder_remove;
179 
180  // NOTE: CSQC's version of setorigin doesn't expand
181  this.absmin -= '1 1 1';
182  this.absmax += '1 1 1';
183 
184  return true;
185 }
186 #endif
#define IL_EACH(this, cond, body)
#define REGISTER_NET_LINKED(id)
Definition: net.qh:67
float speed
Definition: subs.qh:41
skin
Definition: ent_cs.qc:143
#define ReadString
const int WAYPOINTFLAG_LADDER
Definition: api.qh:19
entity() spawn
float DPCONTENTS_BOTCLIP
#define NET_HANDLE(id, param)
Definition: net.qh:12
float DPCONTENTS_PLAYERCLIP
entity to
Definition: self.qh:96
spawnfunc(info_player_attacker)
Definition: sv_assault.qc:283
string classname
Definition: csprogsdefs.qc:107
#define IS_CSQC
Definition: _all.inc:8
vector absmax
Definition: csprogsdefs.qc:92
const float MOVE_NOMONSTERS
Definition: csprogsdefs.qc:253
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
requires that m2>m1 in all coordinates, and that m4>m3
Definition: vector.qh:73
float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
Definition: common.qc:138
float bot_pickup
Definition: api.qh:43
float DPCONTENTS_SOLID
vector trace_endpos
Definition: csprogsdefs.qc:37
entity this
Definition: self.qh:83
const float MASK_NORMAL
Definition: csprogsdefs.qc:164
#define IS_DEAD(s)
Definition: utils.qh:26
float drawmask
Definition: csprogsdefs.qc:95
float waypoint_getlinearcost(float dist)
Definition: waypoints.qc:1012
float nextthink
Definition: csprogsdefs.qc:121
vector(float skel, float bonenum) _skel_get_boneabs_hidden
float MOVETYPE_NOCLIP
Definition: progsdefs.qc:254
const float SOLID_BSP
Definition: csprogsdefs.qc:248
float DPCONTENTS_BODY
float move_time
Definition: movetypes.qh:77
const float SOLID_TRIGGER
Definition: csprogsdefs.qc:245
#define setthink(e, f)
#define strfree(this)
Definition: string.qh:56
float trace_startsolid
Definition: csprogsdefs.qc:35
IntrusiveList g_ladderents
Definition: ladder.qh:3
void
Definition: self.qh:83
vector absmin
Definition: csprogsdefs.qc:92
void waypoint_spawnforteleporter_boxes(entity e, int teleport_flag, vector org1, vector org2, vector destination1, vector destination2, float timetaken)
Definition: waypoints.qc:2015
float time
Definition: csprogsdefs.qc:16
IntrusiveList g_drawables
Definition: main.qh:77
#define IS_PLAYER(v)
Definition: utils.qh:9
void func_ladder_think(entity this)
Definition: ladder.qc:4
float solid
Definition: csprogsdefs.qc:99