3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "extension.h"
33 #include <worldsize.h>
35 class CSMTraceFilter : public CTraceFilter
38 bool ShouldHitEntity(IHandleEntity *pEntity, int contentsMask)
41 m_pFunc->PushCell(gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(pEntity)));
42 m_pFunc->PushCell(contentsMask);
43 m_pFunc->PushCell(m_Data);
44 m_pFunc->Execute(&res);
46 return (res) ? true : false;
48 void SetFunctionPtr(IPluginFunction *pFunc, cell_t data)
54 IPluginFunction *m_pFunc;
58 /* Used for the global trace version */
66 CTraceFilterHitAll g_HitAllFilter;
67 CSMTraceFilter g_SMTraceFilter;
75 static cell_t smn_TRTraceRay(IPluginContext *pContext, const cell_t *params)
77 cell_t *startaddr, *endaddr;
78 pContext->LocalToPhysAddr(params[1], &startaddr);
79 pContext->LocalToPhysAddr(params[2], &endaddr);
81 g_StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
85 case RayType_EndPoint:
87 g_EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
90 case RayType_Infinite:
92 g_DirAngles.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
93 AngleVectors(g_DirAngles, &g_EndVec);
95 /* Make it unitary and get the ending point */
96 g_EndVec.NormalizeInPlace();
97 g_EndVec = g_StartVec + g_EndVec * MAX_TRACE_LENGTH;
102 g_Ray.Init(g_StartVec, g_EndVec);
103 enginetrace->TraceRay(g_Ray, params[3], &g_HitAllFilter, &g_Trace);
108 static cell_t smn_TRTraceHull(IPluginContext *pContext, const cell_t *params)
110 cell_t *startaddr, *endaddr, *mins, *maxs;
111 pContext->LocalToPhysAddr(params[1], &startaddr);
112 pContext->LocalToPhysAddr(params[2], &endaddr);
113 pContext->LocalToPhysAddr(params[3], &mins);
114 pContext->LocalToPhysAddr(params[4], &maxs);
116 g_StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
117 g_HullMins.Init(sp_ctof(mins[0]), sp_ctof(mins[1]), sp_ctof(mins[2]));
118 g_HullMaxs.Init(sp_ctof(maxs[0]), sp_ctof(maxs[1]), sp_ctof(maxs[2]));
119 g_EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
121 g_Ray.Init(g_StartVec, g_EndVec, g_HullMins, g_HullMaxs);
122 enginetrace->TraceRay(g_Ray, params[5], &g_HitAllFilter, &g_Trace);
127 static cell_t smn_TRTraceRayFilter(IPluginContext *pContext, const cell_t *params)
129 cell_t *startaddr, *endaddr;
130 IPluginFunction *pFunc;
133 pFunc = pContext->GetFunctionById(params[5]);
136 return pContext->ThrowNativeError("Invalid function id (%X)", params[5]);
148 g_SMTraceFilter.SetFunctionPtr(pFunc, data);
149 pContext->LocalToPhysAddr(params[1], &startaddr);
150 pContext->LocalToPhysAddr(params[2], &endaddr);
152 g_StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
156 case RayType_EndPoint:
158 g_EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
161 case RayType_Infinite:
163 g_DirAngles.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
164 AngleVectors(g_DirAngles, &g_EndVec);
166 /* Make it unitary and get the ending point */
167 g_EndVec.NormalizeInPlace();
168 g_EndVec = g_StartVec + g_EndVec * MAX_TRACE_LENGTH;
173 g_Ray.Init(g_StartVec, g_EndVec);
174 enginetrace->TraceRay(g_Ray, params[3], &g_SMTraceFilter, &g_Trace);
179 static cell_t smn_TRTraceHullFilter(IPluginContext *pContext, const cell_t *params)
182 IPluginFunction *pFunc;
183 cell_t *startaddr, *endaddr, *mins, *maxs;
185 pFunc = pContext->GetFunctionById(params[6]);
188 return pContext->ThrowNativeError("Invalid function id (%X)", params[5]);
193 g_SMTraceFilter.SetFunctionPtr(pFunc, data);
194 pContext->LocalToPhysAddr(params[1], &startaddr);
195 pContext->LocalToPhysAddr(params[2], &endaddr);
196 pContext->LocalToPhysAddr(params[3], &mins);
197 pContext->LocalToPhysAddr(params[4], &maxs);
199 g_StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
200 g_HullMins.Init(sp_ctof(mins[0]), sp_ctof(mins[1]), sp_ctof(mins[2]));
201 g_HullMaxs.Init(sp_ctof(maxs[0]), sp_ctof(maxs[1]), sp_ctof(maxs[2]));
202 g_EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
204 g_Ray.Init(g_StartVec, g_EndVec, g_HullMins, g_HullMaxs);
205 enginetrace->TraceRay(g_Ray, params[5], &g_SMTraceFilter, &g_Trace);
211 static cell_t smn_TRTraceRayEx(IPluginContext *pContext, const cell_t *params)
213 cell_t *startaddr, *endaddr;
214 pContext->LocalToPhysAddr(params[1], &startaddr);
215 pContext->LocalToPhysAddr(params[2], &endaddr);
217 Vector StartVec, EndVec;
220 StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
224 case RayType_EndPoint:
226 EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
229 case RayType_Infinite:
232 DirAngles.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
233 AngleVectors(DirAngles, &EndVec);
235 /* Make it unitary and get the ending point */
236 EndVec.NormalizeInPlace();
237 EndVec = StartVec + EndVec * MAX_TRACE_LENGTH;
242 trace_t *tr = new trace_t;
243 ray.Init(StartVec, EndVec);
244 enginetrace->TraceRay(ray, params[3], &g_HitAllFilter, tr);
248 if (!(hndl=handlesys->CreateHandle(g_TraceHandle, tr, pContext->GetIdentity(), myself->GetIdentity(), &herr)))
251 return pContext->ThrowNativeError("Unable to create a new trace handle (error %d)", herr);
257 static cell_t smn_TRTraceHullEx(IPluginContext *pContext, const cell_t *params)
259 cell_t *startaddr, *endaddr, *mins, *maxs;
260 pContext->LocalToPhysAddr(params[1], &startaddr);
261 pContext->LocalToPhysAddr(params[2], &endaddr);
262 pContext->LocalToPhysAddr(params[3], &mins);
263 pContext->LocalToPhysAddr(params[4], &maxs);
266 Vector StartVec, EndVec, vmins, vmaxs;
268 StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
269 vmins.Init(sp_ctof(mins[0]), sp_ctof(mins[1]), sp_ctof(mins[2]));
270 vmaxs.Init(sp_ctof(maxs[0]), sp_ctof(maxs[1]), sp_ctof(maxs[2]));
271 EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
273 ray.Init(StartVec, EndVec, vmins, vmaxs);
275 trace_t *tr = new trace_t;
276 enginetrace->TraceRay(ray, params[5], &g_HitAllFilter, tr);
280 if (!(hndl=handlesys->CreateHandle(g_TraceHandle, tr, pContext->GetIdentity(), myself->GetIdentity(), &herr)))
283 return pContext->ThrowNativeError("Unable to create a new trace handle (error %d)", herr);
289 static cell_t smn_TRTraceRayFilterEx(IPluginContext *pContext, const cell_t *params)
291 IPluginFunction *pFunc;
292 cell_t *startaddr, *endaddr;
295 pFunc = pContext->GetFunctionById(params[5]);
298 return pContext->ThrowNativeError("Invalid function id (%X)", params[5]);
300 pContext->LocalToPhysAddr(params[1], &startaddr);
301 pContext->LocalToPhysAddr(params[2], &endaddr);
303 Vector StartVec, EndVec;
304 CSMTraceFilter smfilter;
316 smfilter.SetFunctionPtr(pFunc, data);
317 StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
321 case RayType_EndPoint:
323 EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
326 case RayType_Infinite:
329 DirAngles.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
330 AngleVectors(DirAngles, &EndVec);
332 /* Make it unitary and get the ending point */
333 EndVec.NormalizeInPlace();
334 EndVec = StartVec + EndVec * MAX_TRACE_LENGTH;
339 trace_t *tr = new trace_t;
340 ray.Init(StartVec, EndVec);
341 enginetrace->TraceRay(ray, params[3], &smfilter, tr);
345 if (!(hndl=handlesys->CreateHandle(g_TraceHandle, tr, pContext->GetIdentity(), myself->GetIdentity(), &herr)))
348 return pContext->ThrowNativeError("Unable to create a new trace handle (error %d)", herr);
354 static cell_t smn_TRTraceHullFilterEx(IPluginContext *pContext, const cell_t *params)
356 IPluginFunction *pFunc;
357 cell_t *startaddr, *endaddr, *mins, *maxs;
360 pFunc = pContext->GetFunctionById(params[6]);
363 return pContext->ThrowNativeError("Invalid function id (%X)", params[5]);
365 pContext->LocalToPhysAddr(params[1], &startaddr);
366 pContext->LocalToPhysAddr(params[2], &endaddr);
367 pContext->LocalToPhysAddr(params[3], &mins);
368 pContext->LocalToPhysAddr(params[4], &maxs);
370 Vector StartVec, EndVec, vmins, vmaxs;
371 CSMTraceFilter smfilter;
376 smfilter.SetFunctionPtr(pFunc, data);
377 StartVec.Init(sp_ctof(startaddr[0]), sp_ctof(startaddr[1]), sp_ctof(startaddr[2]));
378 vmins.Init(sp_ctof(mins[0]), sp_ctof(mins[1]), sp_ctof(mins[2]));
379 vmaxs.Init(sp_ctof(maxs[0]), sp_ctof(maxs[1]), sp_ctof(maxs[2]));
380 EndVec.Init(sp_ctof(endaddr[0]), sp_ctof(endaddr[1]), sp_ctof(endaddr[2]));
382 ray.Init(StartVec, EndVec, vmins, vmaxs);
384 trace_t *tr = new trace_t;
385 enginetrace->TraceRay(ray, params[5], &smfilter, tr);
389 if (!(hndl=handlesys->CreateHandle(g_TraceHandle, tr, pContext->GetIdentity(), myself->GetIdentity(), &herr)))
392 return pContext->ThrowNativeError("Unable to create a new trace handle (error %d)", herr);
398 static cell_t smn_TRGetFraction(IPluginContext *pContext, const cell_t *params)
402 HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
404 if (params[1] == BAD_HANDLE)
407 } else if ((err = handlesys->ReadHandle(params[1], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
408 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
411 return sp_ftoc(tr->fraction);
414 static cell_t smn_TRGetPlaneNormal(IPluginContext *pContext, const cell_t *params)
418 HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
420 if (params[1] == BAD_HANDLE)
423 } else if ((err = handlesys->ReadHandle(params[1], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
424 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
427 Vector *normal = &tr->plane.normal;
430 pContext->LocalToPhysAddr(params[2], &r);
431 r[0] = sp_ftoc(normal->x);
432 r[1] = sp_ftoc(normal->y);
433 r[2] = sp_ftoc(normal->z);
439 static cell_t smn_TRGetEndPosition(IPluginContext *pContext, const cell_t *params)
443 HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
445 if (params[2] == BAD_HANDLE)
448 } else if ((err = handlesys->ReadHandle(params[2], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
449 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
453 pContext->LocalToPhysAddr(params[1], &addr);
455 addr[0] = sp_ftoc(tr->endpos.x);
456 addr[1] = sp_ftoc(tr->endpos.y);
457 addr[2] = sp_ftoc(tr->endpos.z);
462 static cell_t smn_TRDidHit(IPluginContext *pContext, const cell_t *params)
466 HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
468 if (params[1] == BAD_HANDLE)
471 } else if ((err = handlesys->ReadHandle(params[1], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
472 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
475 return tr->DidHit() ? 1 : 0;
478 static cell_t smn_TRGetHitGroup(IPluginContext *pContext, const cell_t *params)
482 HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
484 if (params[1] == BAD_HANDLE)
487 } else if ((err = handlesys->ReadHandle(params[1], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
488 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
494 static cell_t smn_TRGetEntityIndex(IPluginContext *pContext, const cell_t *params)
498 HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
500 if (params[1] == BAD_HANDLE)
503 } else if ((err = handlesys->ReadHandle(params[1], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
504 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
507 if (tr->m_pEnt == NULL)
512 return gamehelpers->EntityToBCompatRef(tr->m_pEnt);
515 static cell_t smn_TRGetPointContents(IPluginContext *pContext, const cell_t *params)
518 IHandleEntity *hentity;
522 pContext->LocalToPhysAddr(params[1], &vec);
523 pContext->LocalToPhysAddr(params[2], &ent);
525 pos.x = sp_ctof(vec[0]);
526 pos.y = sp_ctof(vec[1]);
527 pos.z = sp_ctof(vec[2]);
531 mask = enginetrace->GetPointContents(pos);
533 #if SOURCE_ENGINE >= SE_LEFT4DEAD
534 mask = enginetrace->GetPointContents(pos, MASK_ALL, &hentity);
536 mask = enginetrace->GetPointContents(pos, &hentity);
538 *ent = gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(hentity));
544 static cell_t smn_TRGetPointContentsEnt(IPluginContext *pContext, const cell_t *params)
546 /* TODO: See if we can get the collidable with a prop and remove the reliance on edicts */
547 edict_t *pEdict = PEntityOfEntIndex(gamehelpers->ReferenceToIndex(params[1]));
548 if (!pEdict || pEdict->IsFree())
550 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
556 pContext->LocalToPhysAddr(params[2], &addr);
558 pos.x = sp_ctof(addr[0]);
559 pos.y = sp_ctof(addr[1]);
560 pos.z = sp_ctof(addr[2]);
562 return enginetrace->GetPointContents_Collideable(pEdict->GetCollideable(), pos);
565 static cell_t smn_TRPointOutsideWorld(IPluginContext *pContext, const cell_t *params)
570 pContext->LocalToPhysAddr(params[1], &vec);
572 pos.x = sp_ctof(vec[0]);
573 pos.y = sp_ctof(vec[1]);
574 pos.z = sp_ctof(vec[2]);
576 return enginetrace->PointOutsideWorld(pos);
579 sp_nativeinfo_t g_TRNatives[] =
581 {"TR_TraceRay", smn_TRTraceRay},
582 {"TR_TraceHull", smn_TRTraceHull},
583 {"TR_TraceRayEx", smn_TRTraceRayEx},
584 {"TR_TraceHullEx", smn_TRTraceHullEx},
585 {"TR_GetFraction", smn_TRGetFraction},
586 {"TR_GetEndPosition", smn_TRGetEndPosition},
587 {"TR_GetEntityIndex", smn_TRGetEntityIndex},
588 {"TR_DidHit", smn_TRDidHit},
589 {"TR_GetHitGroup", smn_TRGetHitGroup},
590 {"TR_GetPointContents", smn_TRGetPointContents},
591 {"TR_GetPointContentsEnt", smn_TRGetPointContentsEnt},
592 {"TR_TraceRayFilter", smn_TRTraceRayFilter},
593 {"TR_TraceRayFilterEx", smn_TRTraceRayFilterEx},
594 {"TR_TraceHullFilter", smn_TRTraceHullFilter},
595 {"TR_TraceHullFilterEx", smn_TRTraceHullFilterEx},
596 {"TR_GetPlaneNormal", smn_TRGetPlaneNormal},
597 {"TR_PointOutsideWorld", smn_TRPointOutsideWorld},