]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/func/ladder.qc
Remove legacy Quake bbox expansion: bmodel entities
[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 #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)
25                                 IL_PUSH(g_ladderents, it);
26                         it.ladder_entity = this;
27                 }
28         });
29
30 #ifdef SVQC
31         this.nextthink = time;
32 #endif
33 }
34
35 #ifdef SVQC
36 bool func_ladder_send(entity this, entity to, int sf)
37 {
38         WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
39
40         WriteString(MSG_ENTITY, this.classname);
41         WriteByte(MSG_ENTITY, this.skin);
42         WriteCoord(MSG_ENTITY, this.speed);
43
44         trigger_common_write(this, false);
45
46         return true;
47 }
48
49 void func_ladder_link(entity this)
50 {
51         trigger_link(this, func_ladder_send);
52         //this.model = "null";
53 }
54
55 void func_ladder_init(entity this)
56 {
57         WarpZoneLib_ExactTrigger_Init(this, false);
58         BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
59         func_ladder_link(this);
60         setthink(this, func_ladder_think);
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) / 2;
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);
75         if(trace_startsolid)
76         {
77                 tracebox(top_max + stepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
78                 if(trace_startsolid)
79                 {
80                         tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
81                         if(trace_startsolid)
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);
96                                 if(trace_startsolid)
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
127 spawnfunc(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
134 spawnfunc(func_water)
135 {
136         func_ladder_init(this);
137 }
138
139 #elif defined(CSQC)
140 .float speed;
141
142 void func_ladder_draw(entity this) { func_ladder_think(this); }
143
144 void 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
154 NET_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