Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
ladder.qc
Go to the documentation of this file.
1#include "ladder.qh"
2REGISTER_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 if (WarpZoneLib_ExactTrigger_Touch(this, it, false))
23 {
24 if(!it.ladder_entity)
26 it.ladder_entity = this;
27 }
28 });
29
30#ifdef SVQC
31 this.nextthink = time;
32#endif
33}
34
35#ifdef SVQC
36bool func_ladder_send(entity this, entity to, int sf)
37{
38 WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
39
43
44 trigger_common_write(this, false);
45
46 return true;
47}
48
50{
52 //this.model = "null";
53}
54
56{
59 func_ladder_link(this);
61 this.nextthink = time;
62
63 if(min(this.absmax.x - this.absmin.x, this.absmax.y - this.absmin.y) > 100)
64 return;
65
66 entity tracetest_ent = spawn();
67 setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
68 tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
69
70 vector top_min = (this.absmin + this.absmax) * 0.5;
71 top_min.z = this.absmax.z;
72 vector top_max = top_min;
73 top_max.z += PL_MAX_CONST.z - PL_MIN_CONST.z;
74 tracebox(top_max + jumpstepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
76 {
77 tracebox(top_max + stepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
79 {
80 tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
82 {
83 if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
84 && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
85 {
86 // move top on one side
87 top_max.y = top_min.y = this.absmin.y + (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
88 }
89 else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
90 && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
91 {
92 // move top on one side
93 top_max.x = top_min.x = this.absmin.x + (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
94 }
95 tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
97 {
98 if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
99 && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
100 {
101 // alternatively on the other side
102 top_max.y = top_min.y = this.absmax.y - (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
103 }
104 else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
105 && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
106 {
107 // alternatively on the other side
108 top_max.x = top_min.x = this.absmax.x - (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
109 }
110 tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
111 }
112 }
113 }
114 }
115 delete(tracetest_ent);
116 if(trace_startsolid || trace_endpos.z < this.absmax.z)
117 {
118 return;
119 }
120
121 this.bot_pickup = true; // allow bots to make use of this ladder
122 float cost = waypoint_getlinearcost(trace_endpos.z - this.absmin.z);
123 top_min = trace_endpos;
124 waypoint_spawnforteleporter_boxes(this, WAYPOINTFLAG_LADDER, this.absmin, this.absmax, top_min, top_min, cost);
125}
126
127spawnfunc(func_ladder)
128{
129 IL_PUSH(g_ladders, this); // TODO: also func_water? bots currently loop through func_ladder only
130
131 func_ladder_init(this);
132}
133
134spawnfunc(func_water)
135{
136 func_ladder_init(this);
137}
138
139#elif defined(CSQC)
140.float speed;
141
142void func_ladder_draw(entity this) { func_ladder_think(this); }
143
144void func_ladder_remove(entity this)
145{
146 IL_EACH(g_ladderents, it.ladder_entity == this,
147 {
148 it.ladder_entity = NULL;
149 IL_REMOVE(g_ladderents, it);
150 });
151 strfree(this.classname);
152}
153
154NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
155{
156 this.classname = strzone(ReadString());
157 this.skin = ReadByte();
158 this.speed = ReadCoord();
159 this.solid = SOLID_TRIGGER;
160
161 trigger_common_read(this, false);
162
163 if(isnew)
164 IL_PUSH(g_drawables, this);
165 this.draw = func_ladder_draw;
166 this.drawmask = MASK_NORMAL;
167
168 this.move_time = time;
169 this.entremove = func_ladder_remove;
170
171 return true;
172}
173#endif
const int WAYPOINTFLAG_LADDER
Definition api.qh:19
float bot_pickup
Definition api.qh:43
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define ReadString
IntrusiveList g_drawables
Definition main.qh:91
#define IS_DEAD(s)
Definition player.qh:245
#define IS_PLAYER(s)
Definition player.qh:243
const vector PL_MIN_CONST
Definition constants.qh:56
const vector PL_MAX_CONST
Definition constants.qh:55
string classname
const float MOVE_NOMONSTERS
float drawmask
float DPCONTENTS_BOTCLIP
const float SOLID_TRIGGER
float DPCONTENTS_SOLID
const float MASK_NORMAL
float DPCONTENTS_BODY
float effects
float DPCONTENTS_PLAYERCLIP
float skin
float time
vector trace_endpos
float trace_startsolid
float nextthink
vector absmax
const float EF_NODEPTHTEST
vector absmin
#define spawn
float speed
Definition dynlight.qc:9
solid
Definition ent_cs.qc:165
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_EACH(this, cond, body)
#define FOREACH_ENTITY_RADIUS(org, dist, cond, body)
Definition iter.qh:160
void func_ladder_link(entity this)
Definition ladder.qc:49
void func_ladder_init(entity this)
Definition ladder.qc:55
void func_ladder_think(entity this)
Definition ladder.qc:4
bool func_ladder_send(entity this, entity to, int sf)
Definition ladder.qc:36
IntrusiveList g_ladders
Definition ladder.qh:7
IntrusiveList g_ladderents
Definition ladder.qh:3
#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
int ReadByte()
bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher, bool touchfunc)
Definition common.qc:815
#define BITSET_ASSIGN(a, b)
Definition common.qh:104
void WriteString(string data, float dest, float desto)
float vlen(vector v)
void WriteCoord(float data, float dest, float desto)
float min(float f,...)
void WriteByte(float data, float dest, float desto)
string strzone(string s)
float move_time
Definition movetypes.qh:77
const int MOVETYPE_NOCLIP
Definition movetypes.qh:137
vector jumpstepheightvec
Definition navigation.qh:10
vector stepheightvec
Definition navigation.qh:11
#define setthink(e, f)
vector
Definition self.qh:92
entity this
Definition self.qh:72
void
Definition self.qh:72
#define spawnfunc(id)
Definition spawnfunc.qh:96
#define strfree(this)
Definition string.qh:59
void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
Definition triggers.qc:104
void trigger_common_write(entity this, bool withtarget)
Definition triggers.qc:110
void trigger_common_read(entity this, bool withtarget)
void WarpZoneLib_ExactTrigger_Init(entity this, bool unsetmodel)
void waypoint_spawnforteleporter_boxes(entity e, int teleport_flag, vector org1, vector org2, vector destination1, vector destination2, float timetaken)
float waypoint_getlinearcost(float dist)