1
+ #include <sdktools>
2
+
3
+ #pragma newdecls required
4
+ #pragma semicolon 1
5
+
6
+ public Plugin myinfo =
7
+ {
8
+ name = " TPFix" ,
9
+ author = " rio" ,
10
+ description = " Ensure all teleport destinations are a minimum distance off the ground so players dont get stopped" ,
11
+ version = " 1.0.2" ,
12
+ url = " "
13
+ };
14
+
15
+ #define BOTTOM_PAD 2.0
16
+ #define TOP_PAD 0.01
17
+
18
+ bool g_bLate ;
19
+ ArrayList teleportTargets ;
20
+ ArrayList fixedEntities ;
21
+
22
+ char currentmap [64 ];
23
+
24
+ float MINS [3 ] = { - 16.0 , - 16.0 , - BOTTOM_PAD };
25
+ float MAXS [3 ] = { 16.0 , 16.0 , TOP_PAD };
26
+ float HEIGHT = 72.0 ; // height of the player's bounding box while uncrouched
27
+
28
+ public APLRes AskPluginLoad2 (Handle myself , bool late , char [] error , int err_max )
29
+ {
30
+ g_bLate = late ;
31
+ return APLRes_Success ;
32
+ }
33
+
34
+ public void OnPluginStart ()
35
+ {
36
+ teleportTargets = new ArrayList (64 );
37
+ fixedEntities = new ArrayList ();
38
+
39
+ if (g_bLate )
40
+ {
41
+ int entity = - 1 ;
42
+ while ((entity = FindEntityByClassname (entity , " trigger_teleport" )) != - 1 ) CheckTeleport (entity );
43
+ }
44
+ }
45
+
46
+ public void OnMapStart ()
47
+ {
48
+ teleportTargets .Clear ();
49
+ fixedEntities .Clear ();
50
+
51
+ GetCurrentMap (currentmap , sizeof (currentmap ));
52
+ }
53
+
54
+ public void OnTeleportCreated_Delayed (int entity )
55
+ {
56
+ if (IsValidEntity (entity )) CheckTeleport (entity );
57
+ }
58
+
59
+ public void OnEntityCreated_Delayed (int entity )
60
+ {
61
+ if (IsValidEntity (entity ))
62
+ {
63
+ char name [64 ];
64
+ GetEntPropString (entity , Prop_Data , " m_iName" , name , sizeof (name ));
65
+ if (teleportTargets .FindString (name ) != - 1 ) CheckDestination (entity );
66
+ }
67
+ }
68
+
69
+ public void OnEntityCreated (int entity , const char [] classname )
70
+ {
71
+ // delay entity checking so datamaps can be initialized
72
+ if (StrEqual (classname , " trigger_teleport" )) RequestFrame (OnTeleportCreated_Delayed , entity );
73
+ RequestFrame (OnEntityCreated_Delayed , entity );
74
+ }
75
+
76
+ public bool PlayerFilter (int entity , int mask )
77
+ {
78
+ return ! (0 < entity <= MaxClients );
79
+ }
80
+
81
+ void CheckTeleport (int teleportEnt )
82
+ {
83
+ char target [64 ], landmark [64 ];
84
+ if (GetEntPropString (teleportEnt , Prop_Data , " m_target" , target , sizeof (target )) == 0 ) return ;
85
+ if (target [0 ] == ' \0 ' ) return ;
86
+
87
+ // ignore landmarked teleporters
88
+ if (GetEntPropString (teleportEnt , Prop_Data , " m_iLandmark" , landmark , sizeof (landmark )) != 0 ) return ;
89
+
90
+ char target2 [64 ];
91
+ for (int targetEnt = 1 ; targetEnt <= 2048 ; targetEnt ++ )
92
+ {
93
+ if (! IsValidEntity (targetEnt )) continue ;
94
+ if (GetEntPropString (targetEnt , Prop_Data , " m_iName" , target2 , sizeof (target2 )) == 0 ) continue ;
95
+ if (target2 [0 ] == ' \0 ' ) continue ;
96
+ if (StrEqual (target2 , target )) CheckDestination (targetEnt );
97
+ }
98
+
99
+ // store the teleport target name so we can check entities that haven't loaded at this point when they do load
100
+ teleportTargets .PushString (target );
101
+ }
102
+
103
+ void CheckDestination (int targetEnt )
104
+ {
105
+ int ref = EntIndexToEntRef (targetEnt );
106
+ if (fixedEntities .FindValue (ref ) != - 1 ) return ;
107
+ fixedEntities .Push (ref );
108
+
109
+ // if a teleporter is the target of another teleporter, the mapper probably messed up
110
+ // there isn't an easy way to know if it really was a mistake though, so just dont move it
111
+ char classname [128 ];
112
+ GetEntPropString (targetEnt , Prop_Data , " m_iClassname" , classname , sizeof (classname ));
113
+ if (StrEqual (classname , " trigger_teleport" )) return ;
114
+
115
+ char name [64 ];
116
+ GetEntPropString (targetEnt , Prop_Data , " m_iName" , name , sizeof (name ));
117
+
118
+ if (StrEqual (currentmap , " bhop_kz_ethereal" , false ) && StrEqual (name , " room" , false )) return ; // ???
119
+ if (StrEqual (currentmap , " surf_asrown" , false ) && StrEqual (name , " part2" , false )) return ; // ???
120
+
121
+ float origin [3 ], to [3 ], end [3 ];
122
+
123
+ GetEntPropVector (targetEnt , Prop_Send , " m_vecOrigin" , origin );
124
+
125
+ origin [2 ] = origin [2 ] + HEIGHT / 2 ;
126
+ float bottom , top ;
127
+
128
+ to [0 ] = origin [0 ];
129
+ to [1 ] = origin [1 ];
130
+ to [2 ] = origin [2 ] - HEIGHT / 2 - 10 ;
131
+
132
+ TR_TraceHullFilter (origin , to , MINS , MAXS , MASK_PLAYERSOLID_BRUSHONLY , PlayerFilter );
133
+
134
+ if (TR_DidHit ())
135
+ {
136
+ TR_GetEndPosition (end );
137
+ if (origin [2 ] - end [2 ] < HEIGHT / 2 ) bottom = HEIGHT / 2 - (origin [2 ] - end [2 ]);
138
+ }
139
+
140
+ to [0 ] = origin [0 ];
141
+ to [1 ] = origin [1 ];
142
+ to [2 ] = origin [2 ] + HEIGHT / 2 + 10 ;
143
+
144
+ TR_TraceHullFilter (origin , to , MINS , MAXS , MASK_PLAYERSOLID_BRUSHONLY , PlayerFilter );
145
+
146
+ if (TR_DidHit ())
147
+ {
148
+ TR_GetEndPosition (end );
149
+ if (end [2 ] - origin [2 ] < HEIGHT / 2 ) top = HEIGHT / 2 - (end [2 ] - origin [2 ]);
150
+ }
151
+
152
+ origin [2 ] = origin [2 ] - HEIGHT / 2 ;
153
+
154
+ if (top > 0.0 && bottom > 0.0 )
155
+ {
156
+ //PrintToServer("[TPFix] Cannot fix teleport destination \"%s\" (%u)", name, ref);
157
+ return ;
158
+ }
159
+ else if (top > 0.0 )
160
+ {
161
+ //PrintToServer("[TPFix] Adjusting teleport destination \"%s\" (%u) DOWN by %.2f", name, ref, top);
162
+ origin [2 ] = origin [2 ] - top ;
163
+ TeleportEntity (targetEnt , origin , NULL_VECTOR , NULL_VECTOR );
164
+ }
165
+ else if (bottom > 0.0 )
166
+ {
167
+ //PrintToServer("[TPFix] Adjusting teleport destination \"%s\" (%u) UP by %.2f", name, ref, bottom);
168
+ origin [2 ] = origin [2 ] + bottom ;
169
+ TeleportEntity (targetEnt , origin , NULL_VECTOR , NULL_VECTOR );
170
+ }
171
+ }
0 commit comments