]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/func/ladder.qc
d60c28abc81cf04cb54c0d390a4166a8b5c36da8
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mapobjects / func / ladder.qc
1 #include "ladder.qh"
2 REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
3
4 void func_ladder_think(entity this)
5 {
6
7 #ifdef CSQC
8         // TODO: check if this is what is causing the glitchiness when switching between them
9         float dt = time - this.move_time;
10         this.move_time = time;
11         if(dt <= 0) { return; }
12 #endif
13
14         // set myself as current ladders where possible
15         IL_EACH(g_ladderents, it.ladder_entity == this,
16         {
17                 it.ladder_entity = NULL;
18                 IL_REMOVE(g_ladderents, it);
19         });
20
21         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),
22         {
23                 if (WarpZoneLib_ExactTrigger_Touch(this, it, false))
24                 {
25                         if(!it.ladder_entity)
26                                 IL_PUSH(g_ladderents, it);
27                         it.ladder_entity = this;
28                 }
29         });
30
31 #ifdef SVQC
32         this.nextthink = time;
33 #endif
34 }
35
36 #ifdef SVQC
37 bool func_ladder_send(entity this, entity to, int sf)
38 {
39         WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
40
41         WriteString(MSG_ENTITY, this.classname);
42         WriteByte(MSG_ENTITY, this.skin);
43         WriteCoord(MSG_ENTITY, this.speed);
44
45         trigger_common_write(this, false);
46
47         return true;
48 }
49
50 void func_ladder_link(entity this)
51 {
52         trigger_link(this, func_ladder_send);
53         //this.model = "null";
54 }
55
56 void func_ladder_init(entity this)
57 {
58         EXACTTRIGGER_INIT;
59         BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
60         func_ladder_link(this);
61         setthink(this, func_ladder_think);
62         this.nextthink = time;
63
64         if(min(this.absmax.x - this.absmin.x, this.absmax.y - this.absmin.y) > 100)
65                 return;
66
67         entity tracetest_ent = spawn();
68         setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
69         tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
70
71         vector top_min = (this.absmin + this.absmax) / 2;
72         top_min.z = this.absmax.z;
73         vector top_max = top_min;
74         top_max.z += PL_MAX_CONST.z - PL_MIN_CONST.z;
75         tracebox(top_max + jumpstepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
76         if(trace_startsolid)
77         {
78                 tracebox(top_max + stepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
79                 if(trace_startsolid)
80                 {
81                         tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
82                         if(trace_startsolid)
83                         {
84                                 if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
85                                         && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
86                                 {
87                                         // move top on one side
88                                         top_max.y = top_min.y = this.absmin.y + (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
89                                 }
90                                 else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
91                                         && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
92                                 {
93                                         // move top on one side
94                                         top_max.x = top_min.x = this.absmin.x + (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
95                                 }
96                                 tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
97                                 if(trace_startsolid)
98                                 {
99                                         if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
100                                                 && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
101                                         {
102                                                 // alternatively on the other side
103                                                 top_max.y = top_min.y = this.absmax.y - (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
104                                         }
105                                         else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
106                                                 && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
107                                         {
108                                                 // alternatively on the other side
109                                                 top_max.x = top_min.x = this.absmax.x - (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
110                                         }
111                                         tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
112                                 }
113                         }
114                 }
115         }
116         delete(tracetest_ent);
117         if(trace_startsolid || trace_endpos.z < this.absmax.z)
118         {
119                 return;
120         }
121
122         this.bot_pickup = true; // allow bots to make use of this ladder
123         float cost = waypoint_getlinearcost(trace_endpos.z - this.absmin.z);
124         top_min = trace_endpos;
125         waypoint_spawnforteleporter_boxes(this, WAYPOINTFLAG_LADDER, this.absmin, this.absmax, top_min, top_min, cost);
126 }
127
128 spawnfunc(func_ladder)
129 {
130         IL_PUSH(g_ladders, this); // TODO: also func_water? bots currently loop through func_ladder only
131
132         func_ladder_init(this);
133 }
134
135 spawnfunc(func_water)
136 {
137         func_ladder_init(this);
138 }
139
140 #elif defined(CSQC)
141 .float speed;
142
143 void func_ladder_draw(entity this) { func_ladder_think(this); }
144
145 void func_ladder_remove(entity this)
146 {
147         IL_EACH(g_ladderents, it.ladder_entity == this,
148         {
149                 it.ladder_entity = NULL;
150                 IL_REMOVE(g_ladderents, it);
151         });
152         strfree(this.classname);
153 }
154
155 NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
156 {
157         this.classname = strzone(ReadString());
158         this.skin = ReadByte();
159         this.speed = ReadCoord();
160         this.solid = SOLID_TRIGGER;
161
162         trigger_common_read(this, false);
163
164         if(isnew)
165                 IL_PUSH(g_drawables, this);
166         this.draw = func_ladder_draw;
167         this.drawmask = MASK_NORMAL;
168
169         this.move_time = time;
170         this.entremove = func_ladder_remove;
171
172         return true;
173 }
174 #endif