summaryrefslogtreecommitdiff
path: root/sourcemod/scripting/include/gamechaos
diff options
context:
space:
mode:
Diffstat (limited to 'sourcemod/scripting/include/gamechaos')
-rw-r--r--sourcemod/scripting/include/gamechaos/arrays.inc52
-rw-r--r--sourcemod/scripting/include/gamechaos/client.inc300
-rw-r--r--sourcemod/scripting/include/gamechaos/debug.inc19
-rw-r--r--sourcemod/scripting/include/gamechaos/isvalidclient.inc16
-rw-r--r--sourcemod/scripting/include/gamechaos/kreedzclimbing.inc226
-rw-r--r--sourcemod/scripting/include/gamechaos/maths.inc362
-rw-r--r--sourcemod/scripting/include/gamechaos/misc.inc245
-rw-r--r--sourcemod/scripting/include/gamechaos/strings.inc367
-rw-r--r--sourcemod/scripting/include/gamechaos/tempents.inc62
-rw-r--r--sourcemod/scripting/include/gamechaos/tracing.inc242
-rw-r--r--sourcemod/scripting/include/gamechaos/vectors.inc66
11 files changed, 1957 insertions, 0 deletions
diff --git a/sourcemod/scripting/include/gamechaos/arrays.inc b/sourcemod/scripting/include/gamechaos/arrays.inc
new file mode 100644
index 0000000..eba62bb
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/arrays.inc
@@ -0,0 +1,52 @@
+
+#if defined _gamechaos_stocks_arrays_included
+ #endinput
+#endif
+#define _gamechaos_stocks_arrays_included
+
+#define GC_ARRAYS_VERSION 0x01_00_00
+#define GC_ARRAYS_VERSION_STRING "1.0.0"
+
+/**
+ * Copies an array into an arraylist.
+ *
+ * @param array Arraylist Handle.
+ * @param index Index in the arraylist.
+ * @param values Array to copy.
+ * @param size Size of the array to copy.
+ * @param offset Arraylist offset to set.
+ * @return Number of cells copied.
+ * @error Invalid Handle or invalid index.
+ */
+stock int GCSetArrayArrayIndexOffset(ArrayList array, int index, const any[] values, int size, int offset)
+{
+ int cells;
+ for (int i; i < size; i++)
+ {
+ array.Set(index, values[i], offset + i);
+ cells++;
+ }
+ return cells;
+}
+
+/**
+ * Copies an arraylist's specified cells to an array.
+ *
+ * @param array Arraylist Handle.
+ * @param index Index in the arraylist.
+ * @param result Array to copy to.
+ * @param size Size of the array to copy to.
+ * @param offset Arraylist offset.
+ * @return Number of cells copied.
+ * @error Invalid Handle or invalid index.
+ */
+stock int GCCopyArrayArrayIndex(const ArrayList array, int index, any[] result, int size, int offset)
+{
+ int cells;
+ for (int i = offset; i < (size + offset); i++)
+ {
+ result[i] = array.Get(index, i);
+ cells++;
+ }
+ return cells;
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/client.inc b/sourcemod/scripting/include/gamechaos/client.inc
new file mode 100644
index 0000000..cb2114a
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/client.inc
@@ -0,0 +1,300 @@
+
+#if defined _gamechaos_stocks_client_included
+ #endinput
+#endif
+#define _gamechaos_stocks_client_included
+
+#define GC_CLIENT_VERSION 0x01_00_00
+#define GC_CLIENT_VERSION_STRING "1.0.0"
+
+/**
+ * Credit: Don't remember.
+ * Removes a player's weapon from the specified slot.
+ *
+ * @param client Client index.
+ * @param slot Weapon slot.
+ * @return True if removed, false otherwise.
+ */
+stock bool GCRemoveWeaponBySlot(int client, int slot)
+{
+ int entity = GetPlayerWeaponSlot(client, slot);
+ if (IsValidEdict(entity))
+ {
+ RemovePlayerItem(client, entity);
+ AcceptEntityInput(entity, "kill");
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Checks if a client is valid and not the server and optionally, whether he's alive.
+ *
+ * @param client Client index.
+ * @param alive Whether to check alive.
+ * @return True if valid, false otherwise.
+ */
+stock bool GCIsValidClient(int client, bool alive = false)
+{
+ return (client >= 1 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client) && !IsClientSourceTV(client) && (!alive || IsPlayerAlive(client)));
+}
+
+
+
+/**
+ * Gets the value of m_flForwardMove.
+ *
+ * @param client Client index.
+ * @return Value of m_flForwardMove.
+ */
+stock float GCGetClientForwardMove(int client)
+{
+ return GetEntPropFloat(client, Prop_Data, "m_flForwardMove");
+}
+
+/**
+ * Gets the value of m_flSideMove.
+ *
+ * @param client Client index.
+ * @return Value of m_flSideMove.
+ */
+stock float GCGetClientSideMove(int client)
+{
+ return GetEntPropFloat(client, Prop_Data, "m_flSideMove");
+}
+
+/**
+ * Gets the client's abs origin.
+ *
+ * @param client Client index.
+ * @return result Player's origin.
+ */
+stock float[] GCGetClientAbsOriginRet(int client)
+{
+ float result[3]
+ GetClientAbsOrigin(client, result);
+ return result;
+}
+
+/**
+ * Copies the client's velocity to a vector.
+ *
+ * @param client Client index.
+ * @param result Resultant vector.
+ */
+stock void GCGetClientVelocity(int client, float result[3])
+{
+ GetEntPropVector(client, Prop_Data, "m_vecVelocity", result);
+}
+
+/**
+ * Gets the client's velocity (m_vecVelocity).
+ *
+ * @param client Client index.
+ * @return result m_vecVelocity.
+ */
+stock float[] GCGetClientVelocityRet(int client)
+{
+ float result[3]
+ GetEntPropVector(client, Prop_Data, "m_vecVelocity", result);
+ return result
+}
+
+/**
+ * Copies the client's basevelocity to a vector.
+ *
+ * @param client Client index.
+ * @param result Resultant vector.
+ */
+stock void GCGetClientBaseVelocity(int client, float result[3])
+{
+ GetEntPropVector(client, Prop_Data, "m_vecBaseVelocity", result);
+}
+
+/**
+ * Gets the client's basevelocity (m_vecBaseVelocity).
+ *
+ * @param client Client index.
+ * @return result m_vecBaseVelocity.
+ */
+stock float[] GCGetClientBaseVelocityRet(int client)
+{
+ float result[3];
+ GetEntPropVector(client, Prop_Data, "m_vecBaseVelocity", result);
+ return result;
+}
+
+
+/**
+ * Gets the client's "m_flDuckSpeed" value.
+ *
+ * @param client Client index.
+ * @return "m_flDuckSpeed".
+ */
+stock float GCGetClientDuckSpeed(int client)
+{
+ return GetEntPropFloat(client, Prop_Send, "m_flDuckSpeed");
+}
+
+/**
+ * Gets the client's "m_flDuckAmount" value.
+ *
+ * @param client Client index.
+ * @return "m_flDuckAmount".
+ */
+stock float GCGetClientDuckAmount(int client)
+{
+ return GetEntPropFloat(client, Prop_Send, "m_flDuckAmount");
+}
+
+/**
+ * Gets the client's "m_bDucking" value.
+ *
+ * @param client Client index.
+ * @return "m_bDucking".
+ */
+stock int GCGetClientDucking(int client)
+{
+ return GetEntProp(client, Prop_Data, "m_bDucking");
+}
+
+/**
+ * Gets the client's "m_flMaxspeed" value.
+ *
+ * @param client Client index.
+ * @return "m_flMaxspeed".
+ */
+stock float GCGetClientMaxspeed(int client)
+{
+ return GetEntPropFloat(client, Prop_Send, "m_flMaxspeed");
+}
+
+/**
+ * Gets the client's "m_afButtonPressed" value.
+ *
+ * @param client Client index.
+ * @return "m_afButtonPressed".
+ */
+stock int GCGetClientButtonPressed(int client)
+{
+ return GetEntProp(client, Prop_Data, "m_afButtonPressed");
+}
+
+/**
+ * Gets the client's "m_afButtonReleased" value.
+ *
+ * @param client Client index.
+ * @return "m_afButtonReleased".
+ */
+stock int GCGetClientButtonReleased(int client)
+{
+ return GetEntProp(client, Prop_Data, "m_afButtonReleased");
+}
+
+/**
+ * Gets the client's "m_afButtonLast" value.
+ *
+ * @param client Client index.
+ * @return "m_afButtonLast".
+ */
+stock int GCGetClientButtonLast(int client)
+{
+ return GetEntProp(client, Prop_Data, "m_afButtonLast");
+}
+
+/**
+ * Gets the client's "m_afButtonForced" value.
+ *
+ * @param client Client index.
+ * @return "m_afButtonForced".
+ */
+stock int GCGetClientForcedButtons(int client)
+{
+ return GetEntProp(client, Prop_Data, "m_afButtonForced");
+}
+
+/**
+ * Gets the client's "m_flStamina" value.
+ *
+ * @param client Client index.
+ * @return "m_flStamina".
+ */
+stock float GCGetClientStamina(int client)
+{
+ return GetEntPropFloat(client, Prop_Send, "m_flStamina");
+}
+
+
+
+/**
+ * Sets the client's origin.
+ *
+ * @param client Client index.
+ * @param origin New origin.
+ */
+stock void GCSetClientAbsOrigin(int client, const float origin[3])
+{
+ SetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", origin);
+}
+
+/**
+ * Sets the client's velocity.
+ *
+ * @param client Client index.
+ * @param velocity New velocity.
+ */
+stock void GCSetClientVelocity(int client, const float velocity[3])
+{
+ SetEntPropVector(client, Prop_Data, "m_vecVelocity", velocity);
+}
+
+/**
+ * Sets the client's "m_vecAbsVelocity".
+ *
+ * @param client Client index.
+ * @param velocity New "m_vecAbsVelocity".
+ */
+stock void GCSetClientAbsVelocity(int client, const float velocity[3])
+{
+ SetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", velocity);
+}
+
+/**
+ * Sets the client's eye angles.
+ * Ang has to be a 2 member array or more
+ *
+ * @param client Client index.
+ * @param ang New eyeangles.
+ */
+stock void GCSetClientEyeAngles(int client, const float[] ang)
+{
+ SetEntPropFloat(client, Prop_Send, "m_angEyeAngles[0]", ang[0]);
+ SetEntPropFloat(client, Prop_Send, "m_angEyeAngles[1]", ang[1]);
+}
+
+
+/**
+ * Sets the client's "m_flDuckSpeed".
+ *
+ * @param client Client index.
+ * @param value New "m_flDuckSpeed".
+ */
+stock void GCSetClientDuckSpeed(int client, float value)
+{
+ SetEntPropFloat(client, Prop_Send, "m_flDuckSpeed", value);
+}
+
+stock void GCSetClientDuckAmount(int client, float value)
+{
+ SetEntPropFloat(client, Prop_Send, "m_flDuckAmount", value);
+}
+
+stock void GCSetClientForcedButtons(int client, int buttons)
+{
+ SetEntProp(client, Prop_Data, "m_afButtonForced", buttons);
+}
+
+stock void GCSetClientStamina(int client, float stamina)
+{
+ SetEntPropFloat(client, Prop_Send, "m_flStamina", stamina)
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/debug.inc b/sourcemod/scripting/include/gamechaos/debug.inc
new file mode 100644
index 0000000..4e5b7e7
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/debug.inc
@@ -0,0 +1,19 @@
+
+// gamechaos's debug stocks
+// useful stocks for debugging
+
+#if defined _gamechaos_debug_included
+ #endinput
+#endif
+#define _gamechaos_debug_included
+
+#define GC_DEBUG_VERSION 0x1_00_00
+#define GC_DEBUG_VERSION_STRING "1.0.0"
+
+#if defined GC_DEBUG
+ #define GC_ASSERT(%1) if (!(%1))SetFailState("Assertion failed: \""...#%1..."\"")
+ #define GC_DEBUGPRINT(%1) PrintToChatAll(%1)
+#else
+ #define GC_ASSERT(%1)%2;
+ #define GC_DEBUGPRINT(%1)%2;
+#endif
diff --git a/sourcemod/scripting/include/gamechaos/isvalidclient.inc b/sourcemod/scripting/include/gamechaos/isvalidclient.inc
new file mode 100644
index 0000000..bf80246
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/isvalidclient.inc
@@ -0,0 +1,16 @@
+
+#if defined _gamechaos_isvalidclient_client_included
+ #endinput
+#endif
+#define _gamechaos_isvalidclient_client_included
+
+/**
+ * Checks if a client is valid.
+ *
+ * @param client Client index.
+ * @return True if valid, false otherwise.
+ */
+stock bool IsValidClient(int client)
+{
+ return (client >= 0 && client <= MaxClients && IsValidEntity(client) && IsClientConnected(client) && IsClientInGame(client));
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/kreedzclimbing.inc b/sourcemod/scripting/include/gamechaos/kreedzclimbing.inc
new file mode 100644
index 0000000..0cbb828
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/kreedzclimbing.inc
@@ -0,0 +1,226 @@
+//
+// Useful things for making plugins for Kreedz Climbing
+//
+
+#if defined _gamechaos_kreedzclimbing_included
+ #endinput
+#endif
+#define _gamechaos_kreedzclimbing_included
+
+#define GC_KREEDZCLIMBING_VERSION 0x01_00_00
+#define GC_KREEDZCLIMBING_VERSION_STRING "1.0.0"
+
+
+#define MAX_COURSE_SIZE 128 // Reasonable maximum characters a course name can have
+#define COURSE_CVAR_COUNT 20 // the amount of Course<int> cvars
+
+// Kreedz Climbing Client Commands:
+// These may be executed by a player via the console, with / in chat, or via binds.
+
+// specmode - Cycles spectator mode (F3 by default).
+// kz_pause - Pauses the timer.
+// flare - Fires a flare.
+// gototimer | start - Returns to the last pressed start timer.
+// spectate | spec - Enters spectator mode.
+// forcespectator - Becomes a spectator no matter what (force respawns a dead player as well).
+// stoptimer - Instantly stops the player's timer.
+// climb | ct - Respawns at the map spawnpoint.
+// InvalidateTimer - Invalidates the player's timer. An invalid timer can't earn rewards for completing the course. InvalidateTimer 1 displays the message, without the 1 it does not.
+
+// Kreedz Climbing Constants
+
+// Timer state (player->m_Local->Timer_Active)
+#define TIMER_STATE_INVISIBLE 0
+#define TIMER_STATE_ACTIVE 1
+#define TIMER_STATE_INACTIVE 2
+#define TIMER_STATE_PAUSED 3
+
+// Timer flags (player_manager->m_iTimerFlags[32])
+// These are replicated flags for player's timer (most timer data is local to it's own player).
+// Note that these flags are mirrors of data local to the player - they are set to the player's
+// state every frame and cannot be changed.
+
+#define TIMER_FLAG_INVALID (1 << 0)
+#define TIMER_FLAG_ACTIVE (1 << 1) // We need to broadcast this because Timer_State is local only.
+#define TIMER_FLAG_PAUSED (1 << 2) // A paused timer cannot be active and vice versa.
+
+// Environmental Attributes (player->m_iEnvironmentalAttributes)
+#define PLAYER_ENV_ATTRIBUTES_BHOP (1 << 0)
+#define PLAYER_ENV_ATTRIBUTES_SURF (1 << 1)
+#define PLAYER_ENV_ATTRIBUTES_AUTOBHOP (1 << 2)
+#define PLAYER_ENV_ATTRIBUTES_CSGOMOVEMENT (1 << 3)
+#define PLAYER_ENV_ATTRIBUTES_CSGODUCKHULL (1 << 4)
+
+// Movement restriction flags (player->m_iMovementRestrictions) (new version of Environmental Restrictions below)
+#define PLAYER_MOVEMENT_RESTRICTION_NOJUMP (1 << 0)
+#define PLAYER_MOVEMENT_RESTRICTION_NOBHOP (1 << 1)
+#define PLAYER_MOVEMENT_RESTRICTION_NODOUBLEDUCK (1 << 2)
+
+// OBSOLETE: ONLY IN OLD MAPS: Environmental Restrictions (player->m_iEnvironmentalRestrictions), note not flags, complete integer.
+#define PLAYER_ENV_RESTRICTION_NOJUMP 1
+#define PLAYER_ENV_RESTRICTION_NOBHOP 2
+#define PLAYER_ENV_RESTRICTION_BOTH 3
+
+// Cooperative status (player->m_Local.m_multiplayercoursedata.Player1Status, Player2Status etc)
+#define COOPERATIVE_STATUS_NONE 0
+#define COOPERATIVE_STATUS_WAITING 1
+#define COOPERATIVE_STATUS_READY 2
+#define COOPERATIVE_STATUS_TIMER_ACTIVE 3
+#define COOPERATIVE_STATUS_TIMER_COMPLETE 4
+#define COOPERATIVE_STATUS_PLAYER_DISCONNECTED 5 // Player disconnected from server, waiting for them to reconnect.
+#define COOPERATIVE_STATUS_TIMER_PAUSED 6
+
+// Kreedz Climbing Button Constants
+#define IN_CHECKPOINT (1 << 25)
+#define IN_TELEPORT (1 << 26)
+#define IN_SPECTATE (1 << 27)
+//#define IN_AVAILABLE (1 << 28) // Unused
+#define IN_HOOK (1 << 29)
+
+// converts the course id from the obsolete "player_starttimer" event into the course name
+stock void GCCourseidToString(int courseid, char[] course, int size)
+{
+ char szCourseid[16];
+ if (courseid < 1 || courseid > COURSE_CVAR_COUNT)
+ {
+ return;
+ }
+ FormatEx(szCourseid, sizeof(szCourseid), "Course%i", courseid);
+ FindConVar(szCourseid).GetString(course, size);
+}
+
+stock void GCGetCurrentMapCourses(ArrayList &array)
+{
+ if (array == null)
+ {
+ // 1 for endurance bool
+ array = new ArrayList(ByteCountToCells(MAX_COURSE_SIZE) + 1);
+ }
+ else
+ {
+ array.Clear();
+ }
+
+ char course[MAX_COURSE_SIZE];
+
+ int ent;
+ while((ent = FindEntityByClassname(ent, "func_stoptimer")) != -1)
+ {
+ int courseid = GetEntProp(ent, Prop_Data, "CourseID");
+ GCCourseidToString(courseid, course, sizeof(course));
+ array.PushString(course);
+
+ bool endurance = GCIsCourseEndurance(course, ent);
+ array.Set(array.Length - 1, endurance, ByteCountToCells(MAX_COURSE_SIZE));
+ }
+
+ int courseStringtableCount;
+ int courseNamesIdx = FindStringTable("CourseNames");
+ courseStringtableCount = GetStringTableNumStrings(courseNamesIdx);
+
+ for (int i; i < courseStringtableCount; i++)
+ {
+ ReadStringTable(courseNamesIdx, i, course, sizeof(course));
+ array.PushString(course);
+
+ bool endurance = GCIsCourseEndurance(course, ent);
+ array.Set(array.Length - 1, endurance, ByteCountToCells(MAX_COURSE_SIZE));
+ }
+}
+
+stock int GCGetTimerState(int client)
+{
+ return GetEntProp(client, Prop_Send, "Timer_Active");
+}
+
+stock void GCSetTimerState(int client, int timerstate)
+{
+ SetEntProp(client, Prop_Send, "Timer_Active", timerstate);
+}
+
+stock int GCGetPlayerEnvAttributes(int client)
+{
+ return GetEntProp(client, Prop_Send, "m_iEnvironmentalAttributes");
+}
+
+stock void GCSetPlayerEnvAttributes(int client, int attributes)
+{
+ SetEntProp(client, Prop_Send, "m_iEnvironmentalAttributes", attributes);
+}
+
+stock int GCGetPlayerMovementRestrictions(int client)
+{
+ return GetEntProp(client, Prop_Send, "m_iMovementRestrictions");
+}
+
+stock void GCSetPlayerMovementRestrictions(int client, int restrictions)
+{
+ SetEntProp(client, Prop_Send, "m_iMovementRestrictions", restrictions);
+}
+
+stock void GCSetActiveCourse(int client, int course)
+{
+ int ent = FindEntityByClassname(0, "player_manager");
+ int courseOffset = FindSendPropInfo("CPlayerResource", "m_iActiveCourse");
+ SetEntData(ent, courseOffset + (client * 4), course);
+}
+
+stock int GCGetTimerFlags(int client)
+{
+ int ent = FindEntityByClassname(0, "player_manager");
+ int courseOffset = FindSendPropInfo("CPlayerResource", "m_iTimerFlags");
+ return GetEntData(ent, courseOffset + (client * 4));
+}
+
+stock bool GCInvalidateTimer(int client)
+{
+ if (~GCGetTimerFlags(client) & TIMER_FLAG_INVALID)
+ {
+ FakeClientCommand(client, "InvalidateTimer 1");
+ return true;
+ }
+
+ return false;
+}
+
+stock bool GCIsCourseEndurance(char[] course, int ent = -1)
+{
+ if (ent != -1)
+ {
+ if (IsValidEntity(ent))
+ {
+ return !!(GetEntProp(ent, Prop_Data, "m_bEnduranceCourse"));
+ }
+ }
+
+ while ((ent = FindEntityByClassname(ent, "point_climbtimer")) != -1)
+ {
+ if (IsValidEntity(ent))
+ {
+ char buffer[MAX_COURSE_SIZE];
+ GetEntPropString(ent, Prop_Data, "m_strCourseName", buffer, sizeof(buffer));
+
+ if (StrEqual(buffer, course))
+ {
+ return !!(GetEntProp(ent, Prop_Data, "m_bEnduranceCourse"));
+ }
+ }
+ }
+
+ while ((ent = FindEntityByClassname(ent, "func_stoptimer")) != -1)
+ {
+ if (IsValidEntity(ent))
+ {
+ char buffer[MAX_COURSE_SIZE];
+ int courseid = GetEntProp(ent, Prop_Data, "CourseID");
+ GCCourseidToString(courseid, buffer, sizeof(buffer));
+
+ if (StrEqual(buffer, course))
+ {
+ return !!(GetEntProp(ent, Prop_Data, "m_bEnduranceCourse"));
+ }
+ }
+ }
+
+ return false;
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/maths.inc b/sourcemod/scripting/include/gamechaos/maths.inc
new file mode 100644
index 0000000..f3c94af
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/maths.inc
@@ -0,0 +1,362 @@
+
+#if defined _gamechaos_stocks_maths_included
+ #endinput
+#endif
+#define _gamechaos_stocks_maths_included
+
+#define GC_MATHS_VERSION 0x02_00_00
+#define GC_MATHS_VERSION_STRING "2.0.0"
+
+#include <gamechaos/vectors>
+
+#define GC_PI 3.14159265359
+
+#define GC_DEGREES(%1) ((%1) * 180.0 / GC_PI) // convert radians to degrees
+#define GC_RADIANS(%1) ((%1) * GC_PI / 180.0) // convert degrees to radians
+
+#define GC_FLOAT_NAN view_as<float>(0xffffffff)
+#define GC_FLOAT_INFINITY view_as<float>(0x7f800000)
+#define GC_FLOAT_NEGATIVE_INFINITY view_as<float>(0xff800000)
+
+#define GC_FLOAT_LARGEST_POSITIVE view_as<float>(0x7f7fffff)
+#define GC_FLOAT_SMALLEST_NEGATIVE view_as<float>(0xff7fffff)
+
+#define GC_FLOAT_SMALLEST_POSITIVE view_as<float>(0x00000001)
+#define GC_FLOAT_LARGEST_NEGATIVE view_as<float>(0x80000001)
+
+#define GC_INT_MAX 0x7fffffff
+#define GC_INT_MIN 0xffffffff
+
+
+/**
+ * Credit: https://stackoverflow.com/questions/5666222/3d-line-plane-intersection
+ * Determines the point of intersection between a plane defined by a point and a normal vector and a line defined by a point and a direction vector.
+ *
+ * @param planePoint A point on the plane.
+ * @param planeNormal Normal vector of the plane.
+ * @param linePoint A point on the line.
+ * @param lineDirection Direction vector of the line.
+ * @param result Resultant vector.
+ */
+stock void GCLineIntersection(const float planePoint[3], const float planeNormal[3], const float linePoint[3], const float lineDirection[3], float result[3])
+{
+ if (GetVectorDotProduct(planeNormal, lineDirection) == 0)
+ {
+ return;
+ }
+
+ float t = (GetVectorDotProduct(planeNormal, planePoint)
+ - GetVectorDotProduct(planeNormal, linePoint))
+ / GetVectorDotProduct(planeNormal, lineDirection);
+
+ float lineDir[3];
+ lineDir = lineDirection;
+ NormalizeVector(lineDir, lineDir);
+
+ ScaleVector(lineDir, t);
+
+ AddVectors(linePoint, lineDir, result);
+}
+
+/**
+ * Calculates a point according to angles supplied that is a certain distance away.
+ *
+ * @param client Client index.
+ * @param result Resultant vector.
+ * @param distance Maximum distance to trace.
+ * @return True on success, false otherwise.
+ */
+stock void GCCalcPointAngleDistance(const float start[3], const float angle[3], float distance, float result[3])
+{
+ float zsine = Sine(DegToRad(-angle[0]));
+ float zcos = Cosine(DegToRad(-angle[0]));
+
+ result[0] = Cosine(DegToRad(angle[1])) * zcos;
+ result[1] = Sine(DegToRad(angle[1])) * zcos;
+ result[2] = zsine;
+
+ ScaleVector(result, distance);
+ AddVectors(start, result, result);
+}
+
+/**
+ * Compares how close 2 floats are.
+ *
+ * @param z1 Float 1
+ * @param z2 Float 2
+ * @param tolerance How close the floats have to be to return true.
+ * @return True on success, false otherwise.
+ */
+stock bool GCIsRoughlyEqual(float z1, float z2, float tolerance)
+{
+ return FloatAbs(z1 - z2) < tolerance;
+}
+
+/**
+ * Checks if a float is within a range
+ *
+ * @param number Float to check.
+ * @param min Minimum range.
+ * @param max Maximum range.
+ * @return True on success, false otherwise.
+ */
+stock bool GCIsFloatInRange(float number, float min, float max)
+{
+ return number >= min && number <= max;
+}
+
+/**
+ * Keeps the yaw angle within the range of -180 to 180.
+ *
+ * @param angle Angle.
+ * @return Normalised angle.
+ */
+stock float GCNormaliseYaw(float angle)
+{
+ if (angle <= -180.0)
+ {
+ angle += 360.0;
+ }
+
+ if (angle > 180.0)
+ {
+ angle -= 360.0;
+ }
+
+ return angle;
+}
+
+/**
+ * Keeps the yaw angle within the range of -180 to 180.
+ *
+ * @param angle Angle.
+ * @return Normalised angle.
+ */
+stock float GCNormaliseYawRad(float angle)
+{
+ if (angle <= -FLOAT_PI)
+ {
+ angle += FLOAT_PI * 2;
+ }
+
+ if (angle > FLOAT_PI)
+ {
+ angle -= FLOAT_PI * 2;
+ }
+
+ return angle;
+}
+
+/**
+ * Linearly interpolates between 2 values.
+ *
+ * @param f1 Float 1.
+ * @param f2 Float 2.
+ * @param fraction Amount to interpolate.
+ * @return Interpolated value.
+ */
+stock float GCInterpLinear(float f1, float f2, float fraction)
+{
+ float diff = f2 - f1;
+
+ return diff * fraction + f1;
+}
+
+/**
+ * Calculates the linear fraction from a value that was interpolated and 2 values it was interpolated from.
+ *
+ * @param f1 Float 1.
+ * @param f2 Float 2.
+ * @param fraction Interpolated value.
+ * @return Fraction.
+ */
+stock float GCCalcLerpFraction(float f1, float f2, float lerped)
+{
+ float diff = f2 - f1;
+
+ float fraction = lerped - f1 / diff;
+ return fraction;
+}
+
+/**
+ * Calculate absolute value of an integer.
+ *
+ * @param x Integer.
+ * @return Absolute value of integer.
+ */
+stock int GCIntAbs(int x)
+{
+ return x >= 0 ? x : -x;
+}
+
+/**
+ * Get the maximum of 2 integers.
+ *
+ * @param n1 Integer.
+ * @param n2 Integer.
+ * @return The biggest of n1 and n2.
+ */
+stock int GCIntMax(int n1, int n2)
+{
+ return n1 > n2 ? n1 : n2;
+}
+
+/**
+ * Get the minimum of 2 integers.
+ *
+ * @param n1 Integer.
+ * @param n2 Integer.
+ * @return The smallest of n1 and n2.
+ */
+stock int GCIntMin(int n1, int n2)
+{
+ return n1 < n2 ? n1 : n2;
+}
+
+/**
+ * Checks if an integer is within a range
+ *
+ * @param number Integer to check.
+ * @param min Minimum range.
+ * @param max Maximum range.
+ * @return True on success, false otherwise.
+ */
+stock bool GCIsIntInRange(int number, int min, int max)
+{
+ return number >= min && number <= max;
+}
+
+/**
+ * Calculates a float percentage from a common fraction.
+ *
+ * @param numerator Numerator.
+ * @param denominator Denominator.
+ * @return Float percentage. -1.0 on failure.
+ */
+stock float GCCalcIntPercentage(int numerator, int denominator)
+{
+ return float(numerator) / float(denominator) * 100.0;
+}
+
+/**
+ * Integer power.
+ * Returns the base raised to the power of the exponent.
+ * Returns 0 if exponent is negative.
+ *
+ * @param base Base to be raised.
+ * @param exponent Value to raise the base.
+ * @return Value to the power of exponent.
+ */
+stock int GCIntPow(int base, int exponent)
+{
+ if (exponent < 0)
+ {
+ return 0;
+ }
+
+ int result = 1;
+ for (;;)
+ {
+ if (exponent & 1)
+ {
+ result *= base
+ }
+
+ exponent >>= 1;
+
+ if (!exponent)
+ {
+ break;
+ }
+
+ base *= base;
+ }
+ return result;
+}
+
+/**
+ * Swaps the values of 2 variables.
+ *
+ * @param cell1 Cell 1.
+ * @param cell2 Cell 2.
+ */
+stock void GCSwapCells(any &cell1, any &cell2)
+{
+ any temp = cell1;
+ cell1 = cell2;
+ cell2 = temp;
+}
+
+/**
+ * Clamps an int between min and max.
+ *
+ * @param value Float to clamp.
+ * @param min Minimum range.
+ * @param max Maximum range.
+ * @return Clamped value.
+ */
+stock int GCIntClamp(int value, int min, int max)
+{
+ if (value < min)
+ {
+ return min;
+ }
+ if (value > max)
+ {
+ return max;
+ }
+ return value;
+}
+
+/**
+ * Returns the biggest of 2 values.
+ *
+ * @param num1 Number 1.
+ * @param num2 Number 2.
+ * @return Biggest number.
+ */
+stock float GCFloatMax(float num1, float num2)
+{
+ if (num1 > num2)
+ {
+ return num1;
+ }
+ return num2;
+}
+
+/**
+ * Returns the smallest of 2 values.
+ *
+ * @param num1 Number 1.
+ * @param num2 Number 2.
+ * @return Smallest number.
+ */
+stock float GCFloatMin(float num1, float num2)
+{
+ if (num1 < num2)
+ {
+ return num1;
+ }
+ return num2;
+}
+
+/**
+ * Clamps a float between min and max.
+ *
+ * @param value Float to clamp.
+ * @param min Minimum range.
+ * @param max Maximum range.
+ * @return Clamped value.
+ */
+stock float GCFloatClamp(float value, float min, float max)
+{
+ if (value < min)
+ {
+ return min;
+ }
+ if (value > max)
+ {
+ return max;
+ }
+ return value;
+}
diff --git a/sourcemod/scripting/include/gamechaos/misc.inc b/sourcemod/scripting/include/gamechaos/misc.inc
new file mode 100644
index 0000000..f964862
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/misc.inc
@@ -0,0 +1,245 @@
+
+#if defined _gamechaos_stocks_misc_included
+ #endinput
+#endif
+#define _gamechaos_stocks_misc_included
+
+#define GC_MISC_VERSION 0x01_00_00
+#define GC_MISC_VERSION_STRING "1.0.0"
+
+/**
+ * Check if player is overlapping their MOVERIGHT and MOVELEFT buttons.
+ *
+ * @param x Buttons;
+ * @return True if overlapping, false otherwise.
+ */
+stock bool GCIsOverlapping(int buttons)
+{
+ return buttons & IN_MOVERIGHT && buttons & IN_MOVELEFT
+}
+
+/**
+ * Checks if player gained speed.
+ *
+ * @param speed Current player speed.
+ * @param lastspeed Player speed from previous tick.
+ * @return True if player gained speed, false otherwise.
+ */
+stock bool GCIsStrafeSynced(float speed, float lastspeed)
+{
+ return speed > lastspeed;
+}
+
+/**
+ * Checks if the player is not holding down their MOVERIGHT and MOVELEFT buttons.
+ *
+ * @param x Buttons.
+ * @return True if they're not holding either, false otherwise.
+ */
+stock bool GCIsDeadAirtime(int buttons)
+{
+ return !(buttons & IN_MOVERIGHT) && !(buttons & IN_MOVELEFT);
+}
+
+/**
+* Source: https://forums.alliedmods.net/showthread.php?p=2535972
+* Runs a single line of vscript code.
+* NOTE: Dont use the "script" console command, it startes a new instance and leaks memory. Use this instead!
+*
+* @param code The code to run.
+* @noreturn
+*/
+stock void GCRunScriptCode(const char[] code, any ...)
+{
+ static int scriptLogic = INVALID_ENT_REFERENCE;
+
+ if (scriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(scriptLogic))
+ {
+ scriptLogic = EntIndexToEntRef(CreateEntityByName("logic_script"));
+ if (scriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(scriptLogic))
+ {
+ SetFailState("Could not create a 'logic_script' entity.");
+ }
+
+ DispatchSpawn(scriptLogic);
+ }
+
+ char buffer[512];
+ VFormat(buffer, sizeof(buffer), code, 2);
+
+ SetVariantString(buffer);
+ AcceptEntityInput(scriptLogic, "RunScriptCode");
+}
+
+stock void GCTE_SendBeamBox(int client,
+ const float origin[3],
+ const float mins[3],
+ const float maxs[3],
+ int ModelIndex,
+ int HaloIndex = 0,
+ float Life = 3.0,
+ float Width = 2.0,
+ const int Colour[4] = { 255, 255, 255, 255 },
+ float EndWidth = 2.0,
+ int StartFrame = 0,
+ int FrameRate = 0,
+ int FadeLength = 0,
+ float Amplitude = 0.0,
+ int Speed = 0)
+{
+ // credit to some bhop timer by shavit? thanks
+ int pairs[8][3] = { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 } };
+ int edges[12][2] = { { 0, 1 }, { 0, 3 }, { 0, 4 }, { 2, 1 }, { 2, 3 }, { 2, 6 }, { 5, 4 }, { 5, 6 }, { 5, 1 }, { 7, 4 }, { 7, 6 }, { 7, 3 } };
+
+ float corners[8][3];
+ float corner[2][3];
+
+ AddVectors(origin, mins, corner[0]);
+ AddVectors(origin, maxs, corner[1]);
+
+ for (int i = 0; i < 8; i++)
+ {
+ corners[i][0] = corner[pairs[i][0]][0];
+ corners[i][1] = corner[pairs[i][1]][1];
+ corners[i][2] = corner[pairs[i][2]][2];
+ }
+
+ for (int i = 0; i < 12; i++)
+ {
+ TE_SetupBeamPoints(corners[edges[i][0]],
+ corners[edges[i][1]],
+ ModelIndex,
+ HaloIndex,
+ StartFrame,
+ FrameRate,
+ Life,
+ Width,
+ EndWidth,
+ FadeLength,
+ Amplitude,
+ Colour,
+ Speed);
+ TE_SendToClient(client);
+ }
+}
+
+stock void GCTE_SendBeamCross(int client,
+ const float origin[3],
+ int ModelIndex,
+ int HaloIndex = 0,
+ float Life = 3.0,
+ float Width = 2.0,
+ const int Colour[4] = { 255, 255, 255, 255 },
+ float EndWidth = 2.0,
+ int StartFrame = 0,
+ int FrameRate = 0,
+ int FadeLength = 0,
+ float Amplitude = 0.0,
+ int Speed = 0)
+{
+ float points[4][3];
+
+ for (int i; i < 4; i++)
+ {
+ points[i][2] = origin[2];
+ }
+
+ // -x; -y
+ points[0][0] = origin[0] - 8.0;
+ points[0][1] = origin[1] - 8.0;
+
+ // +x; -y
+ points[1][0] = origin[0] + 8.0;
+ points[1][1] = origin[1] - 8.0;
+
+ // +x; +y
+ points[2][0] = origin[0] + 8.0;
+ points[2][1] = origin[1] + 8.0;
+
+ // -x; +y
+ points[3][0] = origin[0] - 8.0;
+ points[3][1] = origin[1] + 8.0;
+
+ //draw cross
+ for (int corner; corner < 4; corner++)
+ {
+ TE_SetupBeamPoints(origin, points[corner], ModelIndex, HaloIndex, StartFrame, FrameRate, Life, Width, EndWidth, FadeLength, Amplitude, Colour, Speed);
+ TE_SendToClient(client);
+ }
+}
+
+stock void GCTE_SendBeamRectangle(int client,
+ const float origin[3],
+ const float mins[3],
+ const float maxs[3],
+ int modelIndex,
+ int haloIndex = 0,
+ float life = 3.0,
+ float width = 2.0,
+ const int colour[4] = { 255, 255, 255, 255 },
+ float endWidth = 2.0,
+ int startFrame = 0,
+ int frameRate = 0,
+ int fadeLength = 0,
+ float amplitude = 0.0,
+ int speed = 0)
+{
+ float vertices[4][3];
+ GCRectangleVerticesFromPoint(vertices, origin, mins, maxs);
+
+ // send the square
+ for (int i; i < 4; i++)
+ {
+ int j = (i == 3) ? (0) : (i + 1);
+ TE_SetupBeamPoints(vertices[i],
+ vertices[j],
+ modelIndex,
+ haloIndex,
+ startFrame,
+ frameRate,
+ life,
+ width,
+ endWidth,
+ fadeLength,
+ amplitude,
+ colour,
+ speed);
+ TE_SendToClient(client);
+ }
+}
+
+/**
+ * Calculates vertices for a rectangle from a point, mins and maxs.
+ *
+ * @param result Vertex array result.
+ * @param origin Origin to offset mins and maxs by.
+ * @param mins Minimum size of the rectangle.
+ * @param maxs Maximum size of the rectangle.
+ * @return True if overlapping, false otherwise.
+ */
+stock void GCRectangleVerticesFromPoint(float result[4][3], const float origin[3], const float mins[3], const float maxs[3])
+{
+ // Vertices are set clockwise starting from top left (-x; -y)
+
+ // -x; -y
+ result[0][0] = origin[0] + mins[0];
+ result[0][1] = origin[1] + mins[1];
+
+ // +x; -y
+ result[1][0] = origin[0] + maxs[0];
+ result[1][1] = origin[1] + mins[1];
+
+ // +x; +y
+ result[2][0] = origin[0] + maxs[0];
+ result[2][1] = origin[1] + maxs[1];
+
+ // -x; +y
+ result[3][0] = origin[0] + mins[0];
+ result[3][1] = origin[1] + maxs[1];
+
+ // z is the same for every vertex
+ for (int vertex; vertex < 4; vertex++)
+ {
+ result[vertex][2] = origin[2];
+ }
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/strings.inc b/sourcemod/scripting/include/gamechaos/strings.inc
new file mode 100644
index 0000000..8ffcb60
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/strings.inc
@@ -0,0 +1,367 @@
+
+#if defined _gamechaos_stocks_strings_included
+ #endinput
+#endif
+#define _gamechaos_stocks_strings_included
+
+// these are used for functions that return strings.
+// you can change these if they're too small/big.
+#define GC_FIXED_BUFFER_SIZE_SMALL 64
+#define GC_FIXED_BUFFER_SIZE_LARGE 4096
+
+/**
+ * Puts the values from a string of integers into an array
+ *
+ * @param string
+ * @param separator
+ * @param array
+ * @param arraysize
+ */
+stock void GCSeparateIntsFromString(const char[] string, const char[] separator, int[] array, int arraysize)
+{
+ char[][] explodedbuffer = new char[arraysize][32];
+
+ ExplodeString(string, separator, explodedbuffer, arraysize, 32);
+
+ for (int i; i < arraysize; i++)
+ {
+ array[i] = StringToInt(explodedbuffer[i]);
+ }
+}
+
+/**
+ * Prints a message to all admins in the chat area.
+ *
+ * @param format Formatting rules.
+ * @param ... Variable number of format parameters.
+ */
+stock void GCPrintToChatAdmins(const char[] format, any ...)
+{
+ char buffer[256];
+
+ for (int i = 1; i <= MaxClients; i++)
+ {
+ if (GCIsValidClient(i))
+ {
+ AdminId id = GetUserAdmin(i);
+ if (!GetAdminFlag(id, Admin_Generic))
+ {
+ continue;
+ }
+ SetGlobalTransTarget(i);
+ VFormat(buffer, sizeof(buffer), format, 2);
+ PrintToChat(i, "%s", buffer);
+ }
+ }
+}
+
+/**
+ * Removes trailings zeroes from a string. Also removes the decimal point if it can.
+ *
+ * @param buffer Buffer to trim.
+ * @return Whether anything was removed.
+ */
+stock bool GCRemoveTrailing0s(char[] buffer)
+{
+ bool removed;
+ int maxlen = strlen(buffer);
+
+ if (maxlen == 0)
+ {
+ return removed;
+ }
+
+ for (int i = maxlen - 1; i > 0 && (buffer[i] == '0' || buffer[i] == '.' || buffer[i] == 0); i--)
+ {
+ if (buffer[i] == 0)
+ {
+ continue;
+ }
+ if (buffer[i] == '.')
+ {
+ buffer[i] = 0;
+ removed = true;
+ break;
+ }
+ buffer[i] = 0;
+ removed = true;
+ }
+ return removed;
+}
+
+/**
+ * Formats time by HHMMSS. Uses ticks for the time.
+ *
+ * @param timeInTicks Time in ticks.
+ * @param tickRate Tickrate.
+ * @param formattedTime String to use for formatting.
+ * @param size String size.
+ */
+stock void GCFormatTickTimeHHMMSS(int timeInTicks, float tickRate, char[] formattedTime, int size)
+{
+ if (timeInTicks <= 0)
+ {
+ FormatEx(formattedTime, size, "-00:00:00");
+ return;
+ }
+
+ int time = RoundFloat(float(timeInTicks) / tickRate * 100.0); // centiseconds
+ int iHours = time / 360000;
+ int iMinutes = time / 6000 - iHours * 6000;
+ int iSeconds = (time - iHours * 360000 - iMinutes * 6000) / 100;
+ int iCentiSeconds = time % 100;
+
+ if (iHours != 0)
+ {
+ FormatEx(formattedTime, size, "%02i:", iHours);
+ }
+ if (iMinutes != 0)
+ {
+ Format(formattedTime, size, "%s%02i:", formattedTime, iMinutes);
+ }
+
+ Format(formattedTime, size, "%s%02i.%02i", formattedTime, iSeconds, iCentiSeconds);
+}
+
+/**
+ * Formats time by HHMMSS. Uses seconds.
+ *
+ * @param seconds Time in seconds.
+ * @param formattedTime String to use for formatting.
+ * @param size String size.
+ * @param decimals Amount of decimals to use for the fractional part.
+ */
+stock void GCFormatTimeHHMMSS(float seconds, char[] formattedTime, int size, int decimals)
+{
+ int iFlooredTime = RoundToFloor(seconds);
+ int iHours = iFlooredTime / 3600;
+ int iMinutes = iFlooredTime / 60 - iHours * 60;
+ int iSeconds = iFlooredTime - iHours * 3600 - iMinutes * 60;
+ int iFraction = RoundToFloor(FloatFraction(seconds) * Pow(10.0, float(decimals)));
+
+ if (iHours != 0)
+ {
+ FormatEx(formattedTime, size, "%02i:", iHours);
+ }
+ if (iMinutes != 0)
+ {
+ Format(formattedTime, size, "%s%02i:", formattedTime, iMinutes);
+ }
+ char szFraction[32];
+ FormatEx(szFraction, sizeof(szFraction), "%i", iFraction);
+
+ int iTest = strlen(szFraction);
+ for (int i; i < decimals - iTest; i++)
+ {
+ Format(szFraction, sizeof(szFraction), "%s%s", "0", szFraction);
+ }
+
+ Format(formattedTime, size, "%s%02i.%s", formattedTime, iSeconds, szFraction);
+}
+
+/**
+ * Encodes and appends a number onto the end of a UTF-8 string.
+ *
+ * @param string String to append to.
+ * @param strsize String size.
+ * @param number Unicode codepoint to encode.
+ */
+stock void GCEncodeUtf8(char[] string, char strsize, int number)
+{
+ // UTF-8 octet sequence (only change digits marked with x)
+ /*
+ Char. number range | UTF-8 octet sequence
+ (hexadecimal) | (binary)
+ --------------------+---------------------------------------------
+ 0000 0000-0000 007F | 0xxxxxxx
+ 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+ 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+ 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ // byte 4 | byte 3 | byte 2 | byte 1*/
+
+ //char encodedChar = 0b_11110000_10000000_10000000_10000000;
+
+ int zeropos = strlen(string);
+
+ if (zeropos >= strsize - 1) // need one byte for null terminator
+ {
+ return;
+ }
+
+ if (number < 0)
+ {
+ //PrintToServer("ERROR: Encode() - Can't encode negative numbers");
+ return;
+ }
+
+ if (number >= 0x110_000)
+ {
+ //PrintToServer("ERROR: Encode() - Number is too big to encode");
+ return;
+ }
+
+ // 1 byte
+ if (number < 0x80)
+ {
+ string[zeropos] = number;
+ string[zeropos + 1] = '\0';
+ }
+ // 2 bytes
+ else if (number < 0x800)
+ {
+ // can't encode if we don't have enough room
+ if (zeropos + 2 >= strsize)
+ {
+ return;
+ }
+
+ string[zeropos] = 0b_1100_0000 | (number >> 6); // don't need to mask out bits over 0x7FF
+ string[zeropos + 1] = 0b_1000_0000 | (number & 0b_0011_1111);
+
+ string[zeropos + 2] = '\0';
+ }
+ // 3 bytes
+ else if (number < 0x10_000)
+ {
+ // can't encode if we don't have enough room
+ if (zeropos + 3 >= strsize)
+ {
+ return;
+ }
+
+ string[zeropos] = 0b_1110_0000 | (number >> 12); // don't need to mask out bits over 0xFFFF
+ string[zeropos + 1] = 0b_1000_0000 | ((number >> 6) & 0b_0011_1111);
+ string[zeropos + 2] = 0b_1000_0000 | (number & 0b_0011_1111);
+
+ string[zeropos + 3] = '\0';
+ }
+ // 4 bytes
+ else if (number < 0x110_000)
+ {
+ // can't encode if we don't have enough room
+ if (zeropos + 4 >= strsize)
+ {
+ return;
+ }
+
+ string[zeropos] = 0b_1111_0000 | (number >> 18); // don't need to mask out bits over 0x10FFFF
+ string[zeropos + 1] = 0b_1000_0000 | ((number >> 12) & 0b_0011_1111);
+ string[zeropos + 2] = 0b_1000_0000 | ((number >> 6) & 0b_0011_1111);
+ string[zeropos + 3] = 0b_1000_0000 | (number & 0b_0011_1111);
+
+ string[zeropos + 4] = '\0';
+ }
+}
+
+// decode a UTF-8 string into an array of unicode codepoints
+/**
+ * Decodes a UTF-8 string into an array of unicode codepoints.
+ *
+ * @param string String to decode.
+ * @param strsize String size.
+ * @param codepoints Array to use to store the codepoints.
+ * @param cplength Array length.
+ */
+stock void GCDecodeUtf8(char[] string, int strsize, int[] codepoints, int cplength)
+{
+ int charindex;
+ int cpindex;
+
+ while (charindex < strsize && cpindex < cplength)
+ {
+ if (string[charindex] == '\0')
+ {
+ break;
+ }
+
+ int bytes = GetCharBytes(string[charindex]);
+
+ switch (bytes)
+ {
+ case 1:
+ {
+ codepoints[cpindex] = string[charindex];
+ }
+ case 2:
+ {
+ codepoints[cpindex] = (string[charindex++] & 0b_0001_1111) << 6; // byte 2
+ codepoints[cpindex] |= string[charindex] & 0b_0011_1111; // byte 1
+ }
+ case 3:
+ {
+ codepoints[cpindex] = (string[charindex++] & 0b_0000_1111) << 12; // byte 3
+ codepoints[cpindex] |= (string[charindex++] & 0b_0011_1111) << 6; // byte 2
+ codepoints[cpindex] |= string[charindex] & 0b_0011_1111; // byte 1
+ }
+ case 4:
+ {
+ codepoints[cpindex] = (string[charindex++] & 0b_0000_0111) << 18; // byte 4
+ codepoints[cpindex] |= (string[charindex++] & 0b_0011_1111) << 12; // byte 3
+ codepoints[cpindex] |= (string[charindex++] & 0b_0011_1111) << 6; // byte 2
+ codepoints[cpindex] |= string[charindex] & 0b_0011_1111; // byte 1
+ }
+ }
+
+ charindex++;
+ cpindex++;
+ }
+}
+
+/**
+ * Converts an integer to a string.
+ * Same as IntToString, but it returns the string.
+ *
+ * @param num Integer to convert.
+ * @return String of the number.
+ */
+stock char[] GCIntToStringRet(int num)
+{
+ char string[GC_FIXED_BUFFER_SIZE_SMALL];
+ IntToString(num, string, sizeof string);
+ return string;
+}
+
+ /**
+ * Converts a floating point number to a string.
+ * Same as FloatToString, but it returns the string.
+ *
+ * @param num Floating point number to convert.
+ * @return String of the number.
+ */
+stock char[] GCFloatToStringRet(float num)
+{
+ char string[GC_FIXED_BUFFER_SIZE_SMALL];
+ FloatToString(num, string, sizeof string);
+ return string;
+}
+
+/**
+ * Formats a string according to the SourceMod format rules (see documentation).
+ * Same as Format, except it returns the formatted string.
+ *
+ * @param format Formatting rules.
+ * @param ... Variable number of format parameters.
+ * @return Formatted string.
+ */
+stock char[] GCFormatReturn(const char[] format, any ...)
+{
+ char string[GC_FIXED_BUFFER_SIZE_LARGE];
+ VFormat(string, sizeof string, format, 2);
+ return string;
+}
+
+/**
+ * Removes whitespace characters from the beginning and end of a string.
+ * Same as TrimString, except it returns the formatted string and
+ * it doesn't modify the passed string.
+ *
+ * @param str The string to trim.
+ * @return Number of bytes written (UTF-8 safe).
+ */
+stock char[] GCTrimStringReturn(char[] str)
+{
+ char string[GC_FIXED_BUFFER_SIZE_LARGE];
+ strcopy(string, sizeof string, str);
+ TrimString(string);
+ return string;
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/tempents.inc b/sourcemod/scripting/include/gamechaos/tempents.inc
new file mode 100644
index 0000000..7ec9b5a
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/tempents.inc
@@ -0,0 +1,62 @@
+
+#if defined _gamechaos_stocks_tempents_included
+ #endinput
+#endif
+#define _gamechaos_stocks_tempents_included
+
+// improved api of some tempents
+
+#define GC_TEMPENTS_VERSION 0x01_00_00
+#define GC_TEMPENTS_VERSION_STRING "1.0.0"
+
+#include <sdktools_tempents>
+
+/**
+ * Sets up a point to point beam effect.
+ *
+ * @param start Start position of the beam.
+ * @param end End position of the beam.
+ * @param modelIndex Precached model index.
+ * @param life Time duration of the beam.
+ * @param width Initial beam width.
+ * @param endWidth Final beam width.
+ * @param colour Color array (r, g, b, a).
+ * @param haloIndex Precached model index.
+ * @param amplitude Beam amplitude.
+ * @param speed Speed of the beam.
+ * @param fadeLength Beam fade time duration.
+ * @param frameRate Beam frame rate.
+ * @param startFrame Initial frame to render.
+ */
+stock void GCTE_SetupBeamPoints(const float start[3],
+ const float end[3],
+ int modelIndex,
+ float life = 2.0,
+ float width = 2.0,
+ float endWidth = 2.0,
+ const int colour[4] = {255, 255, 255, 255},
+ int haloIndex = 0,
+ float amplitude = 0.0,
+ int speed = 0,
+ int fadeLength = 0,
+ int frameRate = 0,
+ int startFrame = 0)
+{
+ TE_Start("BeamPoints");
+ TE_WriteVector("m_vecStartPoint", start);
+ TE_WriteVector("m_vecEndPoint", end);
+ TE_WriteNum("m_nModelIndex", modelIndex);
+ TE_WriteNum("m_nHaloIndex", haloIndex);
+ TE_WriteNum("m_nStartFrame", startFrame);
+ TE_WriteNum("m_nFrameRate", frameRate);
+ TE_WriteFloat("m_fLife", life);
+ TE_WriteFloat("m_fWidth", width);
+ TE_WriteFloat("m_fEndWidth", endWidth);
+ TE_WriteFloat("m_fAmplitude", amplitude);
+ TE_WriteNum("r", colour[0]);
+ TE_WriteNum("g", colour[1]);
+ TE_WriteNum("b", colour[2]);
+ TE_WriteNum("a", colour[3]);
+ TE_WriteNum("m_nSpeed", speed);
+ TE_WriteNum("m_nFadeLength", fadeLength);
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/tracing.inc b/sourcemod/scripting/include/gamechaos/tracing.inc
new file mode 100644
index 0000000..65d54a8
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/tracing.inc
@@ -0,0 +1,242 @@
+
+#if defined _gamechaos_stocks_tracing_included
+ #endinput
+#endif
+#define _gamechaos_stocks_tracing_included
+
+#include <sdktools_trace>
+
+#define GC_TRACING_VERSION 0x01_00_00
+#define GC_TRACING_VERSION_STRING "1.0.0"
+
+/**
+ * Trace ray filter that filters players from being traced.
+ *
+ * @param entity Entity.
+ * @param data Data.
+ * @return True on success, false otherwise.
+ */
+stock bool GCTraceEntityFilterPlayer(int entity, any data)
+{
+ return entity > MAXPLAYERS;
+}
+
+/**
+ * Traces the player hull beneath the player in the direction of
+ * the player's velocity. This should be used on the tick when the player lands
+ *
+ * @param client Player's index.
+ * @param pos Player's position vector.
+ * @param velocity Player's velocity vector. This shuold have the current tick's x and y velocities, but the previous tick's z velocity, since when you're on ground, your z velocity is 0.
+ * @param result Trace endpoint on success, player's position on failure.
+ * @param bugged Whether to add gravity to the player's velocity or not.
+ * @return True on success, false otherwise.
+ */
+stock bool GCTraceLandPos(int client, const float pos[3], const float velocity[3], float result[3], float fGravity, bool bugged = false)
+{
+ float newVel[3];
+ newVel = velocity;
+
+ if (bugged)
+ {
+ // add 0.5 gravity
+ newVel[2] -= fGravity * GetTickInterval() * 0.5;
+ }
+ else
+ {
+ // add 1.5 gravity
+ newVel[2] -= fGravity * GetTickInterval() * 1.5;
+ }
+
+ ScaleVector(newVel, GetTickInterval() * 2.0);
+ float pos2[3];
+ AddVectors(pos, newVel, pos2);
+
+ float mins[3];
+ float maxs[3];
+ GetClientMins(client, mins);
+ GetClientMaxs(client, maxs);
+
+ Handle trace = TR_TraceHullFilterEx(pos, pos2, mins, maxs, MASK_PLAYERSOLID, GCTraceEntityFilterPlayer);
+
+ if (!TR_DidHit(trace))
+ {
+ result = pos;
+ CloseHandle(trace);
+ return false;
+ }
+
+ TR_GetEndPosition(result, trace);
+ CloseHandle(trace);
+
+ return true;
+}
+
+/**
+ * Traces the player hull 2 units straight down beneath the player.
+ *
+ * @param client Player's index.
+ * @param pos Player's position vector.
+ * @param result Trace endpoint on success, player's position on failure.
+ * @return True on success, false otherwise.
+ */
+stock bool GCTraceGround(int client, const float pos[3], float result[3])
+{
+ float mins[3];
+ float maxs[3];
+
+ GetClientMins(client, mins);
+ GetClientMaxs(client, maxs);
+
+ float startpos[3];
+ float endpos[3];
+
+ startpos = pos;
+ endpos = pos;
+
+ endpos[2] -= 2.0;
+
+ TR_TraceHullFilter(startpos, endpos, mins, maxs, MASK_PLAYERSOLID, GCTraceEntityFilterPlayer);
+
+ if (TR_DidHit())
+ {
+ TR_GetEndPosition(result);
+ return true;
+ }
+ else
+ {
+ result = endpos;
+ return false;
+ }
+}
+
+/**
+ * Traces a hull between 2 positions.
+ *
+ * @param pos1 Position 1.
+ * @param pos2 Position 2
+ * @param result Trace endpoint on success, player's position on failure.
+ * @return True on success, false otherwise.
+ */
+stock bool GCTraceBlock(const float pos1[3], const float pos2[3], float result[3])
+{
+ float mins[3] = {-16.0, -16.0, -1.0};
+ float maxs[3] = { 16.0, 16.0, 0.0};
+
+ TR_TraceHullFilter(pos1, pos2, mins, maxs, MASK_PLAYERSOLID, GCTraceEntityFilterPlayer);
+
+ if (TR_DidHit())
+ {
+ TR_GetEndPosition(result);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/**
+ * Traces from player eye position in the direction of where the player is looking.
+ *
+ * @param client Client index.
+ * @param result Resultant vector.
+ * @return True on success, false otherwise.
+ */
+stock bool GCGetEyeRayPosition(int client, float result[3], TraceEntityFilter filter, any data = 0, int flags = MASK_PLAYERSOLID)
+{
+ float start[3];
+ float angle[3];
+
+ GetClientEyePosition(client, start);
+ GetClientEyeAngles(client, angle);
+
+ TR_TraceRayFilter(start, angle, flags, RayType_Infinite, filter, data);
+
+ if (TR_DidHit(INVALID_HANDLE))
+ {
+ TR_GetEndPosition(result, INVALID_HANDLE);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Traces from player eye position in the direction of where the player is looking, up to a certain distance.
+ *
+ * @param client Client index.
+ * @param result Resultant vector.
+ * @param distance Maximum distance to trace.
+ * @return True on success, false otherwise.
+ */
+stock bool GCTraceEyeRayPositionDistance(int client, float result[3], float distance)
+{
+ float start[3];
+ float angle[3];
+
+ GetClientEyePosition(client, start);
+ GetClientEyeAngles(client, angle);
+
+ float endpoint[3];
+ float zsine = Sine(DegToRad(-angle[0]));
+ float zcos = Cosine(DegToRad(-angle[0]));
+
+ endpoint[0] = Cosine(DegToRad(angle[1])) * zcos;
+ endpoint[1] = Sine(DegToRad(angle[1])) * zcos;
+ endpoint[2] = zsine;
+
+ ScaleVector(endpoint, distance);
+ AddVectors(start, endpoint, endpoint);
+
+ TR_TraceRayFilter(start, endpoint, MASK_PLAYERSOLID, RayType_EndPoint, GCTraceEntityFilterPlayer, client);
+
+ if (TR_DidHit())
+ {
+ TR_GetEndPosition(result);
+ return true;
+ }
+
+ result = endpoint;
+ return false;
+}
+
+/**
+ * Traces a hull in a certain direction and distance.
+ *
+ * @param origin Position to trace from.
+ * @param direction Trace direction.
+ * @param mins Minimum size of the hull.
+ * @param maxs Maximum size of the hull.
+ * @param result Resultant vector.
+ * @return True on success, false otherwise.
+ */
+stock bool GCTraceHullDirection(const float origin[3],
+ const float direction[3],
+ const float mins[3],
+ const float maxs[3],
+ float result[3],
+ float distance,
+ TraceEntityFilter filter,
+ any data = 0,
+ int flags = MASK_PLAYERSOLID)
+{
+ float pos2[3];
+ float zsine = Sine(DegToRad(-direction[0]));
+ float zcos = Cosine(DegToRad(-direction[0]));
+
+ pos2[0] = Cosine(DegToRad(direction[1])) * zcos;
+ pos2[1] = Sine(DegToRad(direction[1])) * zcos;
+ pos2[2] = zsine;
+
+ ScaleVector(pos2, distance);
+ AddVectors(origin, pos2, pos2);
+
+ TR_TraceHullFilter(origin, pos2, mins, maxs, flags, filter, data);
+ if (TR_DidHit())
+ {
+ TR_GetEndPosition(result);
+ return true;
+ }
+ result = pos2;
+ return false;
+} \ No newline at end of file
diff --git a/sourcemod/scripting/include/gamechaos/vectors.inc b/sourcemod/scripting/include/gamechaos/vectors.inc
new file mode 100644
index 0000000..79d5e8f
--- /dev/null
+++ b/sourcemod/scripting/include/gamechaos/vectors.inc
@@ -0,0 +1,66 @@
+
+#if defined _gamechaos_stocks_vectors_included
+ #endinput
+#endif
+#define _gamechaos_stocks_vectors_included
+
+#define GC_VECTORS_VERSION 0x01_00_01
+#define GC_VECTORS_VERSION_STRING "1.0.1"
+
+/**
+ * Calculates the horizontal (x, y) length of a vector.
+ *
+ * @param vec Vector.
+ * @return Vector length (magnitude).
+ */
+stock float GCGetVectorLength2D(const float vec[3])
+{
+ float tempVec[3];
+ tempVec = vec;
+ tempVec[2] = 0.0;
+
+ return GetVectorLength(tempVec);
+}
+
+/**
+ * Calculates the horizontal (x, y) distance between 2 vectors.
+ *
+ * @param x Vector 1.
+ * @param y Vector 2.
+ * @param tolerance How close the floats have to be to return true.
+ * @return True on success, false otherwise.
+ */
+stock float GCGetVectorDistance2D(const float x[3], const float y[3])
+{
+ float x2[3];
+ float y2[3];
+
+ x2 = x;
+ y2 = y;
+
+ x2[2] = 0.0;
+ y2[2] = 0.0;
+
+ return GetVectorDistance(x2, y2);
+}
+
+/**
+ * Checks if 2 vectors are exactly equal.
+ *
+ * @param a Vector 1.
+ * @param b Vector 2.
+ * @return True on success, false otherwise.
+ */
+stock bool GCVectorsEqual(const float a[3], const float b[3])
+{
+ bool result = true;
+ for (int i = 0; i < 3; i++)
+ {
+ if (a[i] != b[i])
+ {
+ result = false;
+ break;
+ }
+ }
+ return result;
+} \ No newline at end of file