From c181361dca9b534a067cb002d1bdcef895f240b9 Mon Sep 17 00:00:00 2001 From: Jackz Date: Thu, 14 Nov 2024 08:57:00 -0600 Subject: [PATCH] Update includes --- scripting/include/jutils.inc | 978 +++++++++++++++++++++++++- scripting/include/l4d_info_editor.inc | 94 +++ 2 files changed, 1071 insertions(+), 1 deletion(-) mode change 120000 => 100644 scripting/include/jutils.inc create mode 100644 scripting/include/l4d_info_editor.inc diff --git a/scripting/include/jutils.inc b/scripting/include/jutils.inc deleted file mode 120000 index 0d9a318..0000000 --- a/scripting/include/jutils.inc +++ /dev/null @@ -1 +0,0 @@ -/media/jackz/Stuff/Jackz/Documents/Sourcepawn/scripting/include/jutils.inc \ No newline at end of file diff --git a/scripting/include/jutils.inc b/scripting/include/jutils.inc new file mode 100644 index 0000000..ec2efea --- /dev/null +++ b/scripting/include/jutils.inc @@ -0,0 +1,977 @@ +#if defined _jutils_included + #endinput +#endif +#define _jutils_included + +#define MODEL_FRANCIS "models/survivors/survivor_biker.mdl" +#define MODEL_LOUIS "models/survivors/survivor_manager.mdl" +#define MODEL_ZOEY "models/survivors/survivor_teenangst.mdl" +#define MODEL_BILL "models/survivors/survivor_namvet.mdl" +#define MODEL_NICK "models/survivors/survivor_gambler.mdl" +#define MODEL_COACH "models/survivors/survivor_coach.mdl" +#define MODEL_ELLIS "models/survivors/survivor_mechanic.mdl" +#define MODEL_ROCHELLE "models/survivors/survivor_producer.mdl" +#define MODEL_MINIGUN "models/w_models/weapons/w_minigun.mdl" + +/** Gets a location horizontally X units away from the origin point. Ignores Z-axis. + * @noreturn + */ +stock void GetHorizontalPositionFromOrigin(const float pos[3], const float ang[3], float units, float finalPosition[3]) { + float theta = DegToRad(ang[1]); + finalPosition[0] = units * Cosine(theta) + pos[0]; + finalPosition[1] = units * Sine(theta) + pos[1]; + finalPosition[2] = pos[2]; +} +stock void GetSidePositionFromOrigin(const float pos[3], const float ang[3], float units, float finalPosition[3]) { + float theta = DegToRad(ang[1] + 90.0); + finalPosition[0] = units * Cosine(theta) + pos[0]; + finalPosition[1] = units * Sine(theta) + pos[1]; + finalPosition[2] = pos[2]; +} +stock void GetHorizontalPositionFromClient(int client, float units, float finalPosition[3]) { + float pos[3], ang[3]; + GetClientEyeAngles(client, ang); + GetClientAbsOrigin(client, pos); + + float theta = DegToRad(ang[1]); + pos[0] += units * Cosine(theta); + pos[1] += units * Sine(theta); + finalPosition = pos; +} +stock void GetEntityDimensions(int entity, float size[3]) { + float maxs[3], mins[3]; + GetEntPropVector(entity, Prop_Data, "m_vecMins" , mins); + GetEntPropVector(entity, Prop_Data, "m_vecMaxs" , maxs); + size[0] = maxs[0] - mins[0]; + size[1] = maxs[1] - mins[1]; + size[2] = maxs[2] - mins[2]; +} + // Gets velocity of an entity (ent) toward new origin with speed (fSpeed) - thanks Ryan +stock bool GetVelocityToOrigin(int entity, const float destination[3], const float fSpeed, float outVelocity[3]) { + float srcOrigin[3]; + GetEntPropVector(entity, Prop_Data, "m_vecVelocity", srcOrigin); + // Velocity = Distance / Time + + float fDistance[3]; + fDistance[0] = destination[0] - srcOrigin[0]; + fDistance[1] = destination[1] - srcOrigin[1]; + fDistance[2] = destination[2] - srcOrigin[2]; + + float fTime = (GetVectorDistance(srcOrigin, destination) / fSpeed); + + outVelocity[0] = (destination[0] - srcOrigin[0]) / fTime; + outVelocity[1] = (destination[1] - srcOrigin[1]) / fTime; + outVelocity[2] = (destination[2] - srcOrigin[2]) / fTime; + + return (outVelocity[0] && outVelocity[1] && outVelocity[2]); + } + +//Credits to Timocop for the stock :D +/** +* Runs a single line of vscript code. +* NOTE: Dont use the "script" console command, it starts a new instance and leaks memory. Use this instead! +* +* @param sCode The code to run. +* @noreturn +*/ +stock void L4D2_RunScript(const char[] sCode, any ...) { + static int iScriptLogic = INVALID_ENT_REFERENCE; + if(iScriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(iScriptLogic)) { + iScriptLogic = EntIndexToEntRef(CreateEntityByName("logic_script")); + if(iScriptLogic == INVALID_ENT_REFERENCE|| !IsValidEntity(iScriptLogic)) + SetFailState("Could not create 'logic_script'"); + + DispatchSpawn(iScriptLogic); + } + + static char sBuffer[512]; + VFormat(sBuffer, sizeof(sBuffer), sCode, 2); + + SetVariantString(sBuffer); + AcceptEntityInput(iScriptLogic, "RunScriptCode"); +} +stock void ShowDelayedHintToAll(const char[] format, any ...) { + char buffer[254]; + VFormat(buffer, sizeof(buffer), format, 2); + static int hintInt = 0; + if(hintInt >= 7) { + PrintHintTextToAll("%s",buffer); + hintInt = 0; + } + hintInt++; +} + +stock int GetSurvivorId(const char[] str, bool isL4D1 = false) { + int possibleNumber = StringToInt(str, 10); + if(strlen(str) == 1) { + if(possibleNumber <= 7 && possibleNumber >= 0) { + return possibleNumber; + } + }else if(possibleNumber == 0) { + int survivorId; + char s = CharToLower(str[0]); + if(s == 'b') { + survivorId = isL4D1 ? 0 : 4; + } else if(s == 'z') { + survivorId = isL4D1 ? 1 : 5; + } else if(s == 'l') { + survivorId = isL4D1 ? 2 : 7; + } else if(s == 'f') { + survivorId = isL4D1 ? 3 : 6; + } else if(s == 'n') { + survivorId = 0; + } else if(s == 'r') { + survivorId = 1; + } else if(s == 'e') { + survivorId = 3; + } else if(s == 'c') { + survivorId = 2; + } + return survivorId; + } + return -1; +} +stock int GetL4D2SurvivorId(const char str[16]) { + int possibleNumber = StringToInt(str, 10); + if(strlen(str) == 1) { + if(possibleNumber <= 7 && possibleNumber >= 0) { + return possibleNumber; + } + }else if(possibleNumber == 0) { + if(StrEqual(str, "nick", false)) return 0; + else if(StrEqual(str, "rochelle", false)) return 1; + else if(StrEqual(str, "coach", false)) return 2; + else if(StrEqual(str, "ellis", false)) return 3; + else if(StrEqual(str, "bill", false)) return 0; + else if(StrEqual(str, "zoey", false)) return 5; + else if(StrEqual(str, "francis", false)) return 3; + else if(StrEqual(str, "louis", false)) return 2; + } + return -1; +} +stock bool GetSurvivorModel(int character, char[] model, int modelStrSize) { + switch(character) { + case 0: strcopy(model, modelStrSize, MODEL_NICK); + case 1: strcopy(model, modelStrSize, MODEL_ROCHELLE); + case 2: strcopy(model, modelStrSize, MODEL_COACH); + case 3: strcopy(model, modelStrSize, MODEL_ELLIS); + case 4: strcopy(model, modelStrSize, MODEL_BILL); + case 5: strcopy(model, modelStrSize, MODEL_ZOEY); + case 6: strcopy(model, modelStrSize, MODEL_FRANCIS); + case 7: strcopy(model, modelStrSize, MODEL_LOUIS); + default: return false; + } + return true; +} +stock bool FindSurvivorModel(const char str[16], char[] model, int modelStrSize) { + int possibleNumber = StringToInt(str, 10); + if(strlen(str) == 1 && possibleNumber <= 7 && possibleNumber >= 0) { + switch(possibleNumber) { + case 0: strcopy(model, modelStrSize, MODEL_NICK); + case 1: strcopy(model, modelStrSize, MODEL_ROCHELLE); + case 2: strcopy(model, modelStrSize, MODEL_COACH); + case 3: strcopy(model, modelStrSize, MODEL_ELLIS); + case 4: strcopy(model, modelStrSize, MODEL_BILL); + case 5: strcopy(model, modelStrSize, MODEL_ZOEY); + case 6: strcopy(model, modelStrSize, MODEL_FRANCIS); + case 7: strcopy(model, modelStrSize, MODEL_LOUIS); + default: return false; + } + return true; + }else{ + if(possibleNumber == 0) { + //try to parse str + if(StrEqual(str, "bill", false)) + strcopy(model, modelStrSize, MODEL_BILL); + else if(StrEqual(str, "zoey", false)) + strcopy(model, modelStrSize, MODEL_ZOEY); + else if(StrEqual(str, "francis", false)) + strcopy(model, modelStrSize, MODEL_FRANCIS); + else if(StrEqual(str, "louis", false)) + strcopy(model, modelStrSize, MODEL_LOUIS); + else if(StrEqual(str, "nick", false)) + strcopy(model, modelStrSize, MODEL_NICK); + else if(StrEqual(str, "ellis", false)) + strcopy(model, modelStrSize, MODEL_ELLIS); + else if(StrEqual(str, "rochelle", false)) + strcopy(model, modelStrSize, MODEL_ROCHELLE); + else if(StrEqual(str, "coach", false)) + strcopy(model, modelStrSize, MODEL_COACH); + else + return false; + return true; + } + } + return false; +} +//returns true if model found +stock bool GetSurvivorName(int client, char[] buffer, int length) { + + char modelName[38]; + GetClientModel(client, modelName, sizeof(modelName)); + if(StrContains(modelName,"biker",false) > -1) { + strcopy(buffer, length, "Francis"); + }else if(StrContains(modelName,"teenangst",false) > -1) { + strcopy(buffer, length, "Zoey"); + }else if(StrContains(modelName,"namvet",false) > -1) { + strcopy(buffer, length, "Bill"); + }else if(StrContains(modelName,"manager",false) > -1) { + strcopy(buffer, length, "Louis"); + }else if(StrContains(modelName,"coach",false) > -1) { + strcopy(buffer, length, "Coach"); + }else if(StrContains(modelName,"producer",false) > -1) { + strcopy(buffer, length, "Rochelle"); + }else if(StrContains(modelName,"gambler",false) > -1) { + strcopy(buffer, length, "Nick"); + }else if(StrContains(modelName,"mechanic",false) > -1) { + strcopy(buffer, length, "Ellis"); + }else{ + return false; + } + return true; +} + +stock int GetSurvivorType(const char[] modelName) { + if(StrContains(modelName,"biker",false) > -1) { + return 6; + }else if(StrContains(modelName,"teenangst",false) > -1) { + return 5; + }else if(StrContains(modelName,"namvet",false) > -1) { + return 4; + }else if(StrContains(modelName,"manager",false) > -1) { + return 7; + }else if(StrContains(modelName,"coach",false) > -1) { + return 2; + }else if(StrContains(modelName,"producer",false) > -1) { + return 1; + }else if(StrContains(modelName,"gambler",false) > -1) { + return 0; + }else if(StrContains(modelName,"mechanic",false) > -1) { + return 3; + }else{ + return false; + } +} +stock bool TraceFilter(int entity, int contentsMask) { + if( entity <= MaxClients ) + return false; + return true; +} +stock bool GetGround(int client, float vPos[3], float vAng[3]) { + GetClientAbsOrigin(client, vPos); + vAng = vPos; + vAng[2] += 5.0; + vPos[2] -= 500.0; + + Handle trace = TR_TraceRayFilterEx(vAng, vPos, MASK_SOLID, RayType_EndPoint, TraceFilter); + if(!TR_DidHit(trace)) { + delete trace; + return false; + } + TR_GetEndPosition(vPos, trace); + delete trace; + + GetClientAbsAngles(client, vAng); + return true; +} + +stock int GiveClientWeaponLasers(int client, const char[] wpnName) { + int entity = GiveClientWeapon(client, wpnName); + if(entity != -1) { + SetEntProp(entity, Prop_Send, "m_upgradeBitVec", 4); + } + return entity; +} + +stock int GiveClientWeapon(int client, const char[] wpnName) { + static char sTemp[64]; + float pos[3]; + GetClientAbsOrigin(client, pos); + Format(sTemp, sizeof(sTemp), "weapon_%s", wpnName); + + int entity = CreateEntityByName(sTemp); + if( entity != -1 ) { + DispatchSpawn(entity); + TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR); + + EquipPlayerWeapon(client, entity); + return entity; + }else{ + return -1; + } +} +stock int GetNearestEntity(int client, char[] classname) +{ + int nearestEntity = -1; + float clientVecOrigin[3], entityVecOrigin[3]; + + //Get the distance between the first entity and client + float distance, nearestDistance = -1.0; + + //Find all the entity and compare the distances + int entity = -1; + while ((entity = FindEntityByClassname(entity, classname)) != -1) + { + GetEntPropVector(entity, Prop_Data, "m_vecOrigin", entityVecOrigin); + distance = GetVectorDistance(clientVecOrigin, entityVecOrigin, true); + + if (distance < nearestDistance || nearestDistance == -1.0) + { + nearestEntity = entity; + nearestDistance = distance; + } + } + return nearestEntity; +} + +stock bool IsValidPlayer(int i) { + return IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i); +} +stock bool IsValidTeamPlayer(int i, int team) { + return IsValidPlayer(i) && GetClientTeam(i) == team; +} +stock int GetPrimaryAmmo(int client) { + int weapon = GetPlayerWeaponSlot(client, 0); + if(weapon > -1) + return GetEntProp(weapon, Prop_Send, "m_iClip1"); + else + return -1; +} +stock int GetSecondaryAmmo(int client, int weapon) { + int activeWpn = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon"); + if(activeWpn == weapon) { + int offset = GetEntProp(weapon, Prop_Data, "m_iPrimaryAmmoType"); + return GetEntProp(client, Prop_Send, "m_iAmmo", _, offset); + } else { + return GetEntProp(activeWpn, Prop_Send, "m_iExtraPrimaryAmmo"); + } +} + +stock void SetSecondaryAmmo(int client, int weapon, int ammo) { + int activeWpn = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon"); + if(activeWpn == weapon) { + int offset = GetEntProp(weapon, Prop_Data, "m_iPrimaryAmmoType"); + SetEntProp(client, Prop_Send, "m_iAmmo", ammo, _, offset); + } else { + SetEntProp(activeWpn, Prop_Send, "m_iExtraPrimaryAmmo", ammo); + } +} +stock void CheatCommand(int client, const char[] command, const char[] argument1, const char[] argument2) { + int userFlags = GetUserFlagBits(client); + SetUserFlagBits(client, ADMFLAG_ROOT); + int flags = GetCommandFlags(command); + SetCommandFlags(command, flags & ~FCVAR_CHEAT); + FakeClientCommand(client, "%s %s %s", command, argument1, argument2); + SetCommandFlags(command, flags); + SetUserFlagBits(client, userFlags); +} +//entity abs origin code from here +//http://forums.alliedmods.net/showpost.php?s=e5dce96f11b8e938274902a8ad8e75e9&p=885168&postcount=3 +stock void GetEntityAbsOrigin(int entity, float origin[3]) { + if (entity && IsValidEntity(entity) + && (GetEntSendPropOffs(entity, "m_vecOrigin") != -1) + && (GetEntSendPropOffs(entity, "m_vecMins") != -1) + && (GetEntSendPropOffs(entity, "m_vecMaxs") != -1)) + { + float mins[3], maxs[3]; + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", origin); + GetEntPropVector(entity, Prop_Send, "m_vecMins", mins); + GetEntPropVector(entity, Prop_Send, "m_vecMaxs", maxs); + + origin[0] += (mins[0] + maxs[0]) * 0.5; + origin[1] += (mins[1] + maxs[1]) * 0.5; + origin[2] += (mins[2] + maxs[2]) * 0.5; + } +} +stock bool IsPrimaryWeapon(const char[] wpnName) { + return StrContains(wpnName, "rifle") > -1 + || StrContains(wpnName, "smg") > -1 + || StrContains(wpnName, "weapon_grenade_launcher") > -1 + || StrContains(wpnName, "sniper") > -1 + || StrContains(wpnName, "shotgun") > -1; +} +stock int GetClientWeaponEntIndex(int client, int slot) { + if(slot >= 0 && slot <= 5) { + int wpnRef = GetPlayerWeaponSlot(client, slot); + if(wpnRef != -1) { + int wpn = EntRefToEntIndex(wpnRef); + if(wpn != INVALID_ENT_REFERENCE) { + return wpn; + }else{ + return -1; + } + }else{ + return -1; + } + }else{ + ThrowError("Slot must be a number between 0 and 5"); + return -1; + } +} +stock int GetClientSecondaryWeapon(int client) { + return GetClientWeaponEntIndex(client, 1); +} +stock bool GetClientWeaponName(int client, int slot, char[] name, int nameSize) { + int wpn = GetClientWeaponEntIndex(client, slot); + if(wpn > 0) { + GetEntityClassname(wpn, name, nameSize); + return true; + }else{ + return false; + } +} +stock bool GetClientWeaponNameSmart(int client, int slot, char[] name, int nameSize) { + int wpn = GetPlayerWeaponSlot(client, slot); + if(wpn > 0) { + GetEntityClassname(wpn, name, nameSize); + if(slot == 1 && StrEqual(name, "weapon_melee")) { + GetEntPropString(wpn, Prop_Data, "m_strMapSetScriptName", name, nameSize); + } + return true; + } + return false; +} + +stock int GetClientWeaponNameSmart2(int client, int slot, char[] name, int nameSize) { + int wpn = GetPlayerWeaponSlot(client, slot); + if(wpn > 0) { + GetEntityClassname(wpn, name, nameSize); + if(slot == 1 && StrEqual(name, "weapon_melee")) { + GetEntPropString(wpn, Prop_Data, "m_strMapSetScriptName", name, nameSize); + } else { + Format(name, nameSize, "%s", name[7]); + } + return wpn; + } + return -1; +} + + +stock bool DoesClientHaveWeapon(int client, int slot, const char[] name) { + char wpn[32]; + if(GetClientWeaponName(client, slot, wpn, sizeof(wpn))) { + return StrEqual(wpn, name, false); + }else{ + return false; + } +} + +stock bool DoesClientHaveMelee(int client) { + int wpnEnt = GetClientSecondaryWeapon(client); + if(wpnEnt > -1) { + char wpn[16]; + GetEdictClassname(wpnEnt, wpn, sizeof(wpn)); + return StrEqual(wpn, "weapon_melee"); + }else{ + return false; + } +} + +stock bool IsValidClient(int client, int checkTeam = 0) { + int team = checkTeam > 0 ? GetClientTeam(client) : 0; + return IsClientConnected(client) && IsClientInGame(client) && IsPlayerAlive(client) && team == checkTeam; +} + +stock bool IsClientInSightRange(int client, int target, float angle = 90.0, float distance = 0.0, bool heightcheck = true, bool negativeangle = false) { + if(angle > 360.0 || angle < 0.0) + ThrowError("Angle Max : 360 & Min : 0. %d isn't proper angle.", angle); + else if(!IsValidClient(client)) + ThrowError("Client is not Alive."); + else if(!IsValidClient(target)) + ThrowError("Target is not Alive."); + + float clientPos[3], targetPos[3], angleVector[3], targetVector[3], resultAngle, resultDistance; + + GetClientEyeAngles(client, angleVector); + angleVector[0] = angleVector[2] = 0.0; + GetAngleVectors(angleVector, angleVector, NULL_VECTOR, NULL_VECTOR); + NormalizeVector(angleVector, angleVector); + if(negativeangle) + NegateVector(angleVector); + + GetClientAbsOrigin(client, clientPos); + GetClientAbsOrigin(target, targetPos); + if(heightcheck && distance > 0) + resultDistance = GetVectorDistance(clientPos, targetPos); + clientPos[2] = targetPos[2] = 0.0; + MakeVectorFromPoints(clientPos, targetPos, targetVector); + NormalizeVector(targetVector, targetVector); + + resultAngle = RadToDeg(ArcCosine(GetVectorDotProduct(targetVector, angleVector))); + + if(resultAngle <= angle/2) + { + if(distance > 0) + { + if(!heightcheck) + resultDistance = GetVectorDistance(clientPos, targetPos); + + return distance >= resultDistance; + } + else return true; + } + else return false; +} + +/// Checks if entity is in sight of client. Angle is the FOV, distance to be squared +stock bool IsEntityInSightRange(int client, int target, float angle = 90.0, float distance = 0.0, bool heightcheck = true, bool negativeangle = false) { + if(angle > 360.0 || angle < 0.0) + ThrowError("Angle Max : 360 & Min : 0. %d isn't proper angle.", angle); + else if(!IsClientConnected(client) || !IsClientInGame(client)) + ThrowError("Client is not Alive."); + else if(target <= MaxClients || !IsValidEntity(target)) + ThrowError("Target is not valid entity."); + + + float clientPos[3], targetPos[3], angleVector[3], targetVector[3], resultAngle, resultDistance; + + GetClientEyeAngles(client, angleVector); + angleVector[0] = angleVector[2] = 0.0; + GetAngleVectors(angleVector, angleVector, NULL_VECTOR, NULL_VECTOR); + NormalizeVector(angleVector, angleVector); + if(negativeangle) + NegateVector(angleVector); + + GetClientAbsOrigin(client, clientPos); + GetEntPropVector(target, Prop_Send, "m_vecOrigin", targetPos); + if(heightcheck && distance > 0) + resultDistance = GetVectorDistance(clientPos, targetPos, true); + clientPos[2] = targetPos[2] = 0.0; + MakeVectorFromPoints(clientPos, targetPos, targetVector); + NormalizeVector(targetVector, targetVector); + + resultAngle = RadToDeg(ArcCosine(GetVectorDotProduct(targetVector, angleVector))); + + if(resultAngle <= angle/2) + { + if(distance > 0) + { + if(!heightcheck) + resultDistance = GetVectorDistance(clientPos, targetPos, true); + + return distance >= resultDistance; + } + else return true; + } + else return false; +} +stock void PrintChatToAdmins(const char[] format, any ...) { + char buffer[254]; + VFormat(buffer, sizeof(buffer), format, 2); + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i)) { + AdminId admin = GetUserAdmin(i); + if(admin != INVALID_ADMIN_ID) { + PrintToChat(i, "%s", buffer); + } + } + } + PrintToServer("%s", buffer); +} +#if defined _multicolors_included +stock void CPrintChatToAdmins(const char[] format, any ...) { + char buffer[254]; + VFormat(buffer, sizeof(buffer), format, 2); + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i)) { + AdminId admin = GetUserAdmin(i); + if(admin != INVALID_ADMIN_ID) { + CPrintToChat(i, "%s", buffer); + } + } + } + CPrintToServer("%s", buffer); +} +#endif +stock bool IsValidAdmin(int client, const char[] flags) { + int ibFlags = ReadFlagString(flags); + if ((GetUserFlagBits(client) & ibFlags) == ibFlags) { + return true; + }else if (GetUserFlagBits(client) & ADMFLAG_ROOT) { + return true; + } + return false; +} + +stock float GetNearestEntityDistance(int originEntity, char[] classname) { + float compareVec[3], entityVecOrigin[3]; + GetEntPropVector(originEntity, Prop_Send, "m_vecOrigin", compareVec); + + //Get the distance between the first entity and client + float distance, nearestDistance = -1.0; + + int entity = -1, closest; + while ((entity = FindEntityByClassname(entity, classname)) != -1) + { + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", entityVecOrigin); + distance = GetVectorDistance(compareVec, entityVecOrigin); + // PrintDebug(DEBUG_SPAWNLOGIC, "Comparing %s (id %d) (%.2f,%.2f,%.2f) distance to entity %d (%.2f,%.2f,%.2f) is %.4f", classname, entity, entityVecOrigin[0], entityVecOrigin[1], entityVecOrigin[2], originEntity, compareVec[0], compareVec[1], compareVec[2], distance); + + if (distance < nearestDistance || nearestDistance == -1.0) + { + nearestDistance = distance; + closest = entity; + } + } + return closest > 0 ? nearestDistance : -1.0; +} + +stock int FindNearestEntityInRange(int originEntity, char[] classname, float range) { + float compareVec[3], entityVecOrigin[3]; + GetEntPropVector(originEntity, Prop_Send, "m_vecOrigin", compareVec); + + //Get the distance between the first entity and client + float distance, nearestDistance = -1.0; + + int entity = -1, closest = -1; + while ((entity = FindEntityByClassname(entity, classname)) != -1) { + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", entityVecOrigin); + distance = GetVectorDistance(compareVec, entityVecOrigin); + + if (distance <= range && (distance < nearestDistance || nearestDistance == -1.0)) { + // PrintDebug(DEBUG_SPAWNLOGIC, "Comparing %s (id %d) (%.2f,%.2f,%.2f) distance to entity %d (%.2f,%.2f,%.2f) is %.4f", classname, entity, entityVecOrigin[0], entityVecOrigin[1], entityVecOrigin[2], originEntity, compareVec[0], compareVec[1], compareVec[2], distance); + nearestDistance = distance; + closest = entity; + } + } + return closest; +} + +stock void MakeEntityGlow(int entity, const int color[3], float distance = 1500.0) { + SetEntProp(entity, Prop_Send, "m_iGlowType", 3); + SetEntProp(entity, Prop_Send, "m_nGlowRange", distance); + SetEntProp(entity, Prop_Send, "m_glowColorOverride", color[0] + (color[1] * 256) + (color[2] * 65536)); +} + +//Unless I'm dumb, this does not exist +stock void StringToLower(char[] str) { + int len = strlen(str); + for(int i = 0; i < len; i++) { + str[i] = CharToLower(str[i]); + } +} +stock void StringToUpper(char[] str) { + int len = strlen(str); + for(int i = 0; i < len; i++) { + str[i] = CharToUpper(str[i]); + } +} + +stock int GetRealClient(int bot) { + if(!IsFakeClient(bot)) return -1; + static char netclass[16]; + GetEntityNetClass(bot, netclass, sizeof(netclass)); + if(StrEqual(netclass, "SurvivorBot")) { + int user = GetEntProp(bot, Prop_Send, "m_humanSpectatorUserID"); + if(user > 0) return GetClientOfUserId(user); + } + return -1; +} + +stock int FindIdleBot(int client) { + for(int i = 1; i <= MaxClients; i++ ) { + if(IsClientConnected(i) && IsClientInGame(i) && HasEntProp(i, Prop_Send, "m_humanSpectatorUserID")) { + int realPlayer = GetClientOfUserId(GetEntProp(i, Prop_Send, "m_humanSpectatorUserID")); + if(realPlayer == client) { + return i; + } + } + } + return -1; +} + +stock void SetParent(int child, int parent) { + SetVariantString("!activator"); + AcceptEntityInput(child, "SetParent", parent); +} + +stock void SetParentAttachment(int child, const char[] attachment, bool withOffset = false) { + SetVariantString(attachment); + if(withOffset) + AcceptEntityInput(child, "SetParentAttachmentMaintainOffset"); + else + AcceptEntityInput(child, "SetParentAttachment"); +} + +stock void ClearParent(int child) { + AcceptEntityInput(child, "ClearParent"); +} + +stock void GetForwardVector(float vPos[3], float vAng[3], float vReturn[3], float fDistance) { + float vDir[3]; + GetAngleVectors(vAng, vDir, NULL_VECTOR, NULL_VECTOR); + ScaleVector(vDir, fDistance); + AddVectors(vPos, vDir, vReturn); +} + +stock void GetDirectionVector(float pos1[3], float angle[3], float rVec[3], float distance, float force) { + float endPos[3]; + GetForwardVector(pos1, angle, endPos, distance); + + MakeVectorFromPoints(pos1, endPos, rVec); + NormalizeVector(rVec, rVec); + + ScaleVector(rVec, force); +} + +// Taken from https://gist.github.com/Aeldrion/48c82912f632eec4c8b9da7394b89c5d +stock void HSVToRGB(const float vec[3], float out[3]) { + // Translates HSV color to RGB color + // H: 0.0 - 360.0, S: 0.0 - 100.0, V: 0.0 - 100.0 + // R, G, B: 0.0 - 1.0 + + float hue = vec[0]; + float saturation = vec[1]; + float value = vec[2]; + + float c = (value / 100.0) * (saturation / 100.0); + float x = c * (1.0 - FloatAbs(float(RoundToFloor(hue / 60) % 2) - 1)); + float m = (value / 100.0) - c; + + if (hue >= 0 && hue < 60.0) { + out[0] = c; + out[1] = x; + out[2] = 0.0; + } else if (hue >= 60.0 && hue < 120.0) { + out[0] = x; + out[1] = c; + out[2] = 0.0; + } else if (hue >= 120.0 && hue < 180.0) { + out[0] = 0.0; + out[1] = c; + out[2] = x; + } else if (hue >= 180.0 && hue < 240.0) { + out[0] = 0.0; + out[1] = x; + out[2] = c; + } else if (hue >= 240.0 && hue < 300.0) { + out[0] = x; + out[1] = 0.0; + out[2] = c; + } else if (hue >= 300.0 && hue < 360.0) { + out[0] = c; + out[1] = 0.0; + out[2] = x; + } + + out[0] += m; + out[1] += m; + out[2] += m; + + out[0] * 255.0; + out[1] * 255.0; + out[2] * 255.0; +} +stock void HSVToRGBInt(const float vec[3], int out[3]) { + // Don't initialize memory, just use the existing memory as int out[3], just tell it that is a float + HSVToRGB(vec, view_as(out)); + // Convert float to int: + out[0] = RoundToFloor(view_as(out[0])); + out[1] = RoundToFloor(view_as(out[1])); + out[2] = RoundToFloor(view_as(out[2])); +} + +stock bool GetCursorLocation(int client, float outPos[3]) { + float angle[3]; + GetClientEyePosition(client, outPos); + GetClientEyeAngles(client, angle); + TR_TraceRayFilter(outPos, angle, MASK_SOLID, RayType_Infinite, Filter_IgnorePlayer, client); + if(TR_DidHit()) { + TR_GetEndPosition(outPos); + return true; + } else { + return false; + } +} + +bool Filter_IgnorePlayer(int entity, int mask, int data) { + return entity > 0 && entity != data; +} + +bool Filter_World(int entity, int mask, int data) { + return entity == 0; +} + +// Gets a position from where the cursor is upto distance away (basically <= distance, going against walls) +stock bool GetCursorLimited(int client, float distance, float endPos[3], TraceEntityFilter filter) +{ + if (client > 0 && client <= MaxClients && IsClientInGame(client)) { + float clientEye[3], clientAngle[3], direction[3]; + GetClientEyePosition(client, clientEye); + GetClientEyeAngles(client, clientAngle); + + GetAngleVectors(clientAngle, direction, NULL_VECTOR, NULL_VECTOR); + ScaleVector(direction, distance); + AddVectors(clientEye, direction, endPos); + + TR_TraceRayFilter(clientEye, endPos, MASK_OPAQUE, RayType_EndPoint, filter, client); + if (TR_DidHit(INVALID_HANDLE)) { + TR_GetEndPosition(endPos); + } + return true; + } + + return false; +} + +stock void SetWeaponDelay(int client, float delay) { + int pWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon"); + if (pWeapon > -1) { + SetEntPropFloat(pWeapon, Prop_Send, "m_flNextPrimaryAttack", GetGameTime() + delay); + SetEntPropFloat(pWeapon, Prop_Send, "m_flNextSecondaryAttack", GetGameTime() + delay); + } +} + + +// Sends client a menu selecting a player, see COMMAND_FILTER_* for flags, idPrefix is appended to menu item's id +stock void QueryPlayer(int client, MenuHandler handler, int flags = COMMAND_FILTER_NO_IMMUNITY, const char[] title = "Select a player", const char[] idPrefix = "", int time = 0) { + Menu menu = new Menu(handler); + menu.SetTitle(title, client); + char id[32], display[32]; + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && (IsClientInGame(i) || flags & COMMAND_FILTER_CONNECTED)) { + if(flags & COMMAND_FILTER_NO_BOTS && IsFakeClient(i)) continue; + if(flags & COMMAND_FILTER_ALIVE && !IsPlayerAlive(i)) continue; + if(flags & COMMAND_FILTER_DEAD && IsPlayerAlive(i)) continue; + if(~flags & COMMAND_FILTER_NO_IMMUNITY && !CanUserTarget(client, i)) continue; + + Format(id, sizeof(id), "%s%d", idPrefix, GetClientUserId(i)); + if(IsFakeClient(i)) { + int realPlayer = GetRealClient(i); + if(realPlayer > 0) { + if(IsPlayerAlive(i)) { + Format(display, sizeof(display), "%N (Idle)", realPlayer); + } else { + Format(display, sizeof(display), "%N (Idle)(Dead)", realPlayer); + } + } else if(IsPlayerAlive(i)) { + Format(display, sizeof(display), "%N", i); + } else { + Format(display, sizeof(display), "%N (dead)", i); + } + } else if(IsPlayerAlive(i)) { + Format(display, sizeof(display), "%N", i); + } else { + Format(display, sizeof(display), "%N (dead)", i); + } + + menu.AddItem(id, display); + } + } + + menu.Display(client, time); +} +stock bool IsNearGround(int ref, float distFromGround = 15.0) { + static float sPos[3], ePos[3]; + GetEntPropVector(ref, Prop_Send, "m_vecOrigin", sPos); + ePos[0] = sPos[0]; + ePos[1] = sPos[1]; + ePos[2] = sPos[2] -= 15.0; + TR_TraceRayFilter(sPos, ePos, MASK_SOLID, RayType_EndPoint, Filter_IgnorePlayer, ref); + if(TR_DidHit()) { + return true; + } + return false; +} + +stock bool IsAreaClear(const float pos[3], const float ang[3], const float minBound[3], const float maxBound[3]) { + + TR_TraceHullFilter(pos, pos, minBound, maxBound, MASK_SOLID, Filter_World); + if(TR_DidHit()) { + return false; + } + return true; +} + +stock Action Timer_KillEntity(Handle h, int entity) { + RemoveEntity(entity); + return Plugin_Handled; +} + +stock int GetSinglePlayer(int client, const char[] input, int flags = 0) { + flags |= COMMAND_FILTER_NO_MULTI; + char buf[2]; + int target_list[1], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + input, + client, + target_list, + 1, + flags, + buf, + 2, + tn_is_ml)) <= 0 + ) { + ReplyToTargetError(client, target_count); + return -1; + } + return target_list[0]; +} + +#if defined _l4dh_included +static int _glowColor[3] = { 255, 255, 255 }; + +stock void GlowPoint(const float pos[3], float lifetime = 5.0) { + PrecacheModel("models/props_fortifications/orange_cone001_reference.mdl"); + int entity = CreateEntityByName("prop_dynamic"); + DispatchKeyValue(entity, "disableshadows", "1"); + DispatchKeyValue(entity, "model", "models/props_fortifications/orange_cone001_reference.mdl"); + TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR); + DispatchSpawn(entity); + L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, _glowColor, false); + CreateTimer(lifetime, Timer_KillEntity, entity); +} + +stock void GlowEntity(int entity, float lifetime = 10.0, int glowColor[3] = _glowColor) { + L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, glowColor, false); + if(lifetime > 0.0) + CreateTimer(lifetime, Timer_ClearGlow, EntIndexToEntRef(entity)); +} + +Action Timer_ClearGlow(Handle h, int ref) { + L4D2_RemoveEntityGlow(ref); + return Plugin_Handled; +} +#endif + +stock bool CompareVector(const float a[3], const float b[3], float delta) { + return a[0] < b[0] + delta && a[0] > b[0] - delta && + a[1] < b[1] + delta && a[1] > b[1] - delta && + a[2] < b[2] + delta && a[2] > b[2] - delta +} + +stock void CalculateWorldPosition(int entity, float pos[3]) { + float mins[3], maxs[3]; + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos); + GetEntPropVector(entity, Prop_Send, "m_vecMins", mins); + GetEntPropVector(entity, Prop_Send, "m_vecMaxs", maxs); + pos[0] = pos[0] + (mins[0] + maxs[0]) * 0.5; + pos[1] = pos[1] + (mins[1] + maxs[1]) * 0.5; + pos[2] = pos[2] + (mins[2] + maxs[2]) * 0.5; +} +#if defined _l4dh_included +/// Displays either: Username, Username (AFK), Username (Dead), Userame (AFK/Dead) +stock void GetMenuDisplayName(int client, char[] display, int maxlen) { + int realPlayer = L4D_GetIdlePlayerOfBot(client); + // Incase player is idle, grab their bot instead of them + if(realPlayer > 0 && IsClientConnected(realPlayer)) { + if(IsPlayerAlive(client)) + Format(display, maxlen, "%N (AFK)", realPlayer); + else + Format(display, maxlen, "%N (AFK/Dead)", realPlayer); + } else if(!IsPlayerAlive(client)) + Format(display, maxlen, "%N (Dead)", client); + else { + GetClientName(client, display, maxlen); + } +} +#endif + +stock int MathMax(int a, int b) { + return a > b ? a : b; +} + +stock int MathMin(int a, int b) { + return a < b ? a : b; +} \ No newline at end of file diff --git a/scripting/include/l4d_info_editor.inc b/scripting/include/l4d_info_editor.inc new file mode 100644 index 0000000..14a1fcf --- /dev/null +++ b/scripting/include/l4d_info_editor.inc @@ -0,0 +1,94 @@ +/* +* Info Editor +* Copyright (C) 2022 Silvers +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#if defined _info_editor_included + #endinput +#endif +#define _info_editor_included + + + +public SharedPlugin __pl_info_editor_ = +{ + name = "info_editor", + file = "l4d_info_editor.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_info_editor__SetNTVOptional() +{ + MarkNativeAsOptional("InfoEditor_GetString"); + MarkNativeAsOptional("InfoEditor_SetString"); + MarkNativeAsOptional("InfoEditor_ReloadData"); +} +#endif + + + +/** + * Retrieves the value of a specified key from the games mission info keyvalue system. "N/A" is returned when not found. + * + * @param pThis Enter the pThis value from OnGetMissionInfo/OnGetWeaponsInfo. Can specify 0 when reading Mission data. + * @param keyname Key name to check. + * @param dest Destination string buffer to copy to. + * @param destLen Destination buffer length (includes null terminator). + * + * @noreturn + */ +native void InfoEditor_GetString(int pThis, const char[] keyname, char[] dest, int destLen); + +/** + * Sets the value of a specified key from the games mission info keyvalue system. + * + * @param pThis Enter the pThis value from OnGetMissionInfo/OnGetWeaponsInfo. Can specify 0 when writing Mission data. + * @param keyname Key name to set. + * @param value Value to set. + * @param create Optionally create the keyvalue if it doesn't exist. + * + * @noreturn + */ +native void InfoEditor_SetString(int pThis, const char[] keyname, const char[] value, bool create = false); + +/** + * Reloads the mission and weapons data configs and forces the game to reload them. + * + * @noreturn + */ +native void InfoEditor_ReloadData(); + + + +/** + * @brief Fired multiple times when the mission info data is parsed. + * + * @param pThis This pointer used for InfoEditor_GetString/InfoEditor_SetString. + */ +forward void OnGetMissionInfo(int pThis); + +/** + * Fired multiple times when the weapon info data is parsed for a specific weapon classname. + * + * @param pThis This pointer used for InfoEditor_GetString/InfoEditor_SetString. + * @param classname Classname of the weapon being parsed. + */ +forward void OnGetWeaponsInfo(int pThis, const char[] classname); \ No newline at end of file