Merge branch 'master' into terencehill/bot_waypoints
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / func / ladder.qc
1 #include "ladder.qh"
2 REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
3
4 void func_ladder_touch(entity this, entity toucher)
5 {
6 #ifdef SVQC
7         if (!toucher.iscreature)
8                 return;
9         if(IS_VEHICLE(toucher))
10                 return;
11 #elif defined(CSQC)
12         if(!toucher.isplayermodel)
13                 return;
14 #endif
15
16         EXACTTRIGGER_TOUCH(this, toucher);
17
18         toucher.ladder_time = time + 0.1;
19         toucher.ladder_entity = this;
20 }
21
22 #ifdef SVQC
23 bool func_ladder_send(entity this, entity to, int sf)
24 {
25         WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
26
27         WriteString(MSG_ENTITY, this.classname);
28         WriteByte(MSG_ENTITY, this.skin);
29         WriteCoord(MSG_ENTITY, this.speed);
30
31         trigger_common_write(this, false);
32
33         return true;
34 }
35
36 void func_ladder_link(entity this)
37 {
38         trigger_link(this, func_ladder_send);
39         //this.model = "null";
40 }
41
42 void func_ladder_init(entity this)
43 {
44         settouch(this, func_ladder_touch);
45         trigger_init(this);
46         func_ladder_link(this);
47
48         if(min(this.absmax.x - this.absmin.x, this.absmax.y - this.absmin.y) > 100)
49                 return;
50
51         entity tracetest_ent = spawn();
52         setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
53         tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
54
55         vector top_min = (this.absmin + this.absmax) / 2;
56         top_min.z = this.absmax.z;
57         vector top_max = top_min;
58         top_max.z += PL_MAX_CONST.z - PL_MIN_CONST.z;
59         tracebox(top_max + jumpstepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
60         if(trace_startsolid)
61         {
62                 tracebox(top_max + stepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
63                 if(trace_startsolid)
64                 {
65                         tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
66                         if(trace_startsolid)
67                         {
68                                 if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
69                                         && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
70                                 {
71                                         // move top on one side
72                                         top_max.y = top_min.y = this.absmin.y + (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
73                                 }
74                                 else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
75                                         && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
76                                 {
77                                         // move top on one side
78                                         top_max.x = top_min.x = this.absmin.x + (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
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                                                 // alternatively on the other side
87                                                 top_max.y = top_min.y = this.absmax.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                                                 // alternatively on the other side
93                                                 top_max.x = top_min.x = this.absmax.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                                 }
97                         }
98                 }
99         }
100         if(trace_startsolid || trace_endpos.z < this.absmax.z)
101         {
102                 delete(tracetest_ent);
103                 return;
104         }
105
106         this.bot_pickup = true; // allow bots to make use of this ladder
107         float cost = waypoint_getlinearcost(trace_endpos.z - this.absmin.z);
108         top_min = trace_endpos;
109         waypoint_spawnforteleporter_boxes(this, WAYPOINTFLAG_LADDER, this.absmin, this.absmax, top_min, top_min, cost);
110 }
111
112 spawnfunc(func_ladder)
113 {
114         IL_PUSH(g_ladders, this); // TODO: also func_water? bots currently loop through func_ladder only
115
116         func_ladder_init(this);
117 }
118
119 spawnfunc(func_water)
120 {
121         func_ladder_init(this);
122 }
123
124 #elif defined(CSQC)
125 .float speed;
126
127 void func_ladder_remove(entity this)
128 {
129         if(this.classname) { strunzone(this.classname); }
130         this.classname = string_null;
131 }
132
133 NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
134 {
135         this.classname = strzone(ReadString());
136         this.skin = ReadByte();
137         this.speed = ReadCoord();
138
139         trigger_common_read(this, false);
140
141         this.solid = SOLID_TRIGGER;
142         settouch(this, func_ladder_touch);
143         this.drawmask = MASK_NORMAL;
144         this.move_time = time;
145         this.entremove = func_ladder_remove;
146
147         return true;
148 }
149 #endif