diff --git a/regamedll/build.gradle b/regamedll/build.gradle index 40e94de6..7d71b778 100644 --- a/regamedll/build.gradle +++ b/regamedll/build.gradle @@ -186,7 +186,7 @@ class RegamedllSrc { h.regamedll_src(CppSourceSet) { source { - srcDirs "engine", "dlls", "game_shared", "pm_shared", "regamedll", "public", "version" + srcDirs "engine", "dlls", "dlls/addons", "game_shared", "pm_shared", "regamedll", "public", "version" include "**/*.cpp" exclude "precompiled.cpp" diff --git a/regamedll/dlls/addons/trigger_setorigin.cpp b/regamedll/dlls/addons/trigger_setorigin.cpp new file mode 100644 index 00000000..c09af1a5 --- /dev/null +++ b/regamedll/dlls/addons/trigger_setorigin.cpp @@ -0,0 +1,361 @@ +#include "precompiled.h" + +LINK_ENTITY_TO_CLASS(trigger_setorigin, CTriggerSetOrigin, CCSTriggerSetOrigin) + +void CTriggerSetOrigin::KeyValue(KeyValueData *pkvd) +{ + if (FStrEq(pkvd->szKeyName, "triggerstate")) + { + int type = Q_atoi(pkvd->szValue); + switch (type) + { + case 0: + m_triggerType = USE_OFF; + break; + case 2: + m_triggerType = USE_TOGGLE; + break; + default: + m_triggerType = USE_ON; + break; + } + + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "copypointer")) + { + m_copyPointer = ALLOC_STRING(pkvd->szValue); + } + else if (FStrEq(pkvd->szKeyName, "offset")) + { + UTIL_StringToVector(m_vecOffset, pkvd->szValue, ' '); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "angleoffset")) + { + UTIL_StringToVector(m_vecAngleOffset, pkvd->szValue, ' '); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "invert_x")) + { + m_bAngleInvertX = Q_atoi(pkvd->szValue) ? true : false; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "invert_y")) + { + m_bAngleInvertY = Q_atoi(pkvd->szValue) ? true : false; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "invert_z")) + { + m_bAngleInvertZ = Q_atoi(pkvd->szValue) ? true : false; + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "m_fRotate")) + { + pev->spawnflags |= SF_SETORIGIN_LOCK_OFFSETS; + pkvd->fHandled = TRUE; + } + else + { + CBaseDelay::KeyValue(pkvd); + } +} + +void CTriggerSetOrigin::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) +{ + if (!(pev->spawnflags & SF_SETORIGIN_CONST_UPDATE)) + { + m_bSetupEntities = true; + return; + } + + switch (useType) + { + case USE_OFF: + m_bUpdateEntities = false; + break; + + case USE_ON: + m_bUpdateEntities = true; + break; + + case USE_TOGGLE: + m_bUpdateEntities = !m_bUpdateEntities; + break; + } + + if (m_bUpdateEntities) + { + m_bSetupEntities = true; + } +} + +void CTriggerSetOrigin::UpdateTick() +{ + if (m_bSetupEntities) + { + SetupEntities(); + } + + if (m_bUpdateEntities) + { + UpdateKnownEntities(); + } +} + +void CTriggerSetOrigin::SetupEntities() +{ + EntityHandle hPrevEnt(m_hCopyPointer); + + m_bSetupEntities = false; + m_entityNum = 0; + + m_hCopyPointer = UTIL_FindEntityByTargetname(m_hCopyPointer, STRING(m_copyPointer)); + + if (!m_hCopyPointer.IsValid() && hPrevEnt.IsValid()) + { + m_hCopyPointer = hPrevEnt; + } + + CBaseEntity *pEntity = nullptr; + while ((pEntity = UTIL_FindEntityByTargetname(pEntity, STRING(pev->target)))) + { + if (m_entityNum > MAX_SETORIGIN_ENTITIES) + break; + + if (FNullEnt(pEntity)) + continue; + + if (m_hCopyPointer.IsValid() && !FNullEnt(m_hCopyPointer.Get())) + { + bool bForceCopy = false; + if (!(pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_X) && + !(pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Y) && + !(pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Z) && + !(pev->spawnflags & SF_SETORIGIN_COPY_AXIS_X) && + !(pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Y) && + !(pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Z)) + { + bForceCopy = true; + } + + if (!(pev->spawnflags & SF_SETORIGIN_SKIP_INITIAL)) + { + Vector vecCopy(pEntity->pev->origin); + + // copy axis X + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_X) || bForceCopy) + vecCopy.x = m_hCopyPointer->pev->origin.x; + + // copy axis Y + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Y) || bForceCopy) + vecCopy.y = m_hCopyPointer->pev->origin.y; + + // copy axis Z + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Z) || bForceCopy) + vecCopy.z = m_hCopyPointer->pev->origin.z; + + // copy angles X + if (pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_X) + pEntity->pev->angles.x = m_hCopyPointer->pev->angles.x; + + if (m_bAngleInvertX) + pEntity->pev->angles.x = UTIL_AngleMod(-pEntity->pev->angles.x); + + // copy angles Y + if (pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Y) + pEntity->pev->angles.y = m_hCopyPointer->pev->angles.y; + + if (m_bAngleInvertY) + pEntity->pev->angles.y = UTIL_AngleMod(-pEntity->pev->angles.y); + + // copy angles Z + if (pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Z) + pEntity->pev->angles.z = m_hCopyPointer->pev->angles.z; + + if (m_bAngleInvertZ) + pEntity->pev->angles.z = UTIL_AngleMod(-pEntity->pev->angles.z); + + pEntity->pev->origin = vecCopy + m_vecOffset; + pEntity->pev->angles = pEntity->pev->angles + m_vecAngleOffset; + + UTIL_SetOrigin(pEntity->pev, pEntity->pev->origin); + } + + m_hEntities [m_entityNum] = pEntity; + m_vecEntities[m_entityNum] = pEntity->pev->origin - m_hCopyPointer->pev->origin; + + Vector vecForward, vecRight, vecUp; + UTIL_MakeVectorsPrivate(m_hCopyPointer->pev->angles, vecForward, vecRight, vecUp); + m_vecEntities[m_entityNum++] *= vecForward + vecRight + vecUp; + } + else + { + pEntity->pev->origin = pEntity->pev->origin + m_vecOffset; + pEntity->pev->angles = pEntity->pev->angles + m_vecAngleOffset; + + UTIL_SetOrigin(pev, pEntity->pev->origin); + } + } + + if (pev->spawnflags & SF_SETORIGIN_REMOVEFIRE) + { + UTIL_Remove(this); + } +} + +void CTriggerSetOrigin::UpdateKnownEntities() +{ + bool bUpdated = false; + for (int i = 0; i < MAX_SETORIGIN_ENTITIES; i++) + { + auto &pEntity = m_hEntities[i]; + if (!pEntity.IsValid()) + { + pEntity = nullptr; + continue; + } + + if (!m_hCopyPointer.IsValid()) + { + m_bUpdateEntities = false; + break; + } + + bool bForceCopy = false; + if (!(pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_X) && + !(pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Y) && + !(pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Z) && + !(pev->spawnflags & SF_SETORIGIN_COPY_AXIS_X) && + !(pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Y) && + !(pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Z)) + { + bForceCopy = true; + } + + if (pev->spawnflags & SF_SETORIGIN_LOCK_OFFSETS) + { + Vector vecForward, vecRight, vecUp; + Vector vecAxisX(g_vecZero), vecAxisY(g_vecZero), vecAxisZ(g_vecZero); + + UTIL_MakeVectorsPrivate(m_hCopyPointer->pev->angles, vecForward, vecRight, vecUp); + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_X) || bForceCopy) + vecAxisX = m_vecEntities[i].x * vecForward; + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Y) || bForceCopy) + vecAxisY = m_vecEntities[i].y * vecRight; + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Z) || bForceCopy) + vecAxisZ = m_vecEntities[i].z * vecUp; + + Vector vecCopy(m_hCopyPointer->pev->origin + vecAxisX + vecAxisY + vecAxisZ); + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_X) || bForceCopy) + pEntity->pev->origin.x = vecCopy.x; + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Y) || bForceCopy) + pEntity->pev->origin.y = vecCopy.y; + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Z) || bForceCopy) + pEntity->pev->origin.z = vecCopy.z; + } + else + { + Vector vecCopy(pEntity->pev->origin); + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_X) || bForceCopy) + vecCopy.x = m_hCopyPointer->pev->origin.x; + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Y) || bForceCopy) + vecCopy.y = m_hCopyPointer->pev->origin.y; + + if ((pev->spawnflags & SF_SETORIGIN_COPY_AXIS_Z) || bForceCopy) + vecCopy.z = m_hCopyPointer->pev->origin.z; + + pEntity->pev->origin = vecCopy + m_vecOffset; + } + + // copy angles Y + if (pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_X) + pEntity->pev->angles.x = UTIL_AngleMod(m_hCopyPointer->pev->angles.x); + + if (m_bAngleInvertX) + pEntity->pev->angles.x = UTIL_AngleMod(-pEntity->pev->angles.x); + + // copy angles X + if (pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Y) + pEntity->pev->angles.y = UTIL_AngleMod(m_hCopyPointer->pev->angles.y); + + if (m_bAngleInvertY) + pEntity->pev->angles.y = UTIL_AngleMod(-pEntity->pev->angles.y); + + // copy angles Z + if (pev->spawnflags & SF_SETORIGIN_COPY_ANGLE_Z) + pEntity->pev->angles.z = UTIL_AngleMod(m_hCopyPointer->pev->angles.z); + + if (m_bAngleInvertZ) + pEntity->pev->angles.z = UTIL_AngleMod(-pEntity->pev->angles.z); + + pEntity->pev->angles += m_vecAngleOffset; + + pEntity->pev->groundentity = nullptr; + pEntity->pev->flags &= ~FL_ONGROUND; + + bUpdated = true; + UTIL_SetOrigin(pEntity->pev, pEntity->pev->origin); + } + + if (!bUpdated) + { + m_bUpdateEntities = false; + } +} + +void CTriggerSetOrigin::OnCreate() +{ + m_bUpdateEntities = false; + m_bSetupEntities = false; + + CTriggerSetOriginManager::getInstance()->Add(this); +} + +void CTriggerSetOrigin::OnDestroy() +{ + CTriggerSetOriginManager::getInstance()->Remove(this); +} + +void CTriggerSetOriginManager::Add(CTriggerSetOrigin *pInstance) +{ + if (!pInstance) + return; + + m_Entities.AddToTail(pInstance); +} + +void CTriggerSetOriginManager::Remove(CTriggerSetOrigin *pInstance) +{ + if (!pInstance) + return; + + m_Entities.FindAndRemove(pInstance); +} + +void CTriggerSetOriginManager::Update() +{ + for (int i = 0; i < m_Entities.Count(); i++) + { + if (!m_Entities[i].IsValid()) + { + m_Entities.Remove(i); + + // Move iterator to back, because Remove method makes shift elements + i--; + continue; + } + + // Update trigger + m_Entities[i]->UpdateTick(); + } +} diff --git a/regamedll/dlls/addons/trigger_setorigin.h b/regamedll/dlls/addons/trigger_setorigin.h new file mode 100644 index 00000000..4749d942 --- /dev/null +++ b/regamedll/dlls/addons/trigger_setorigin.h @@ -0,0 +1,109 @@ +/* +* +* 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 2 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, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#define SF_SETORIGIN_CONST_UPDATE BIT(0) // The entity will constantly update position if set +#define SF_SETORIGIN_REMOVEFIRE BIT(2) // The entity will be removed after firing. + +#define SF_SETORIGIN_LOCK_OFFSETS BIT(3) // Save the offset between the Target entity and the Copy pointer, + // apply offset when updating the Target entity's position (Requires "Constant" flag) + +#define SF_SETORIGIN_COPY_ANGLE_X BIT(4) +#define SF_SETORIGIN_COPY_ANGLE_Y BIT(5) +#define SF_SETORIGIN_COPY_ANGLE_Z BIT(6) + +#define SF_SETORIGIN_COPY_AXIS_X BIT(7) +#define SF_SETORIGIN_COPY_AXIS_Y BIT(8) +#define SF_SETORIGIN_COPY_AXIS_Z BIT(9) + +#define SF_SETORIGIN_SKIP_INITIAL BIT(10) // If you're using the Constant flag, check this box to NOT move the origin of the entity or set the angles initially. + // If you're not using the Constant flag, make sure this isn't enabled or trigger_setorigin won't do anything. + // + // This allows the "Constant" + "offset difference" combination to work as intended from the entity's original location. + // + // You would leave this off if you needed to move the entity to an initial position before having it follow another entity. + // (If this isn't set, trigger_setorigin will move the entity to it's copypointer's origin before doing the offset difference calculation) + +const int MAX_SETORIGIN_ENTITIES = 64; + +class CTriggerSetOrigin: public CBaseDelay { +public: + virtual void Spawn() {}; + virtual void KeyValue(KeyValueData *pkvd); + virtual int ObjectCaps() { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + + virtual void OnCreate(); + virtual void OnDestroy(); + +protected: + friend class CTriggerSetOriginManager; + void UpdateTick(); + void SetupEntities(); + void UpdateKnownEntities(); + +private: + EntityHandle m_hCopyPointer; + EntityHandle m_hEntities[MAX_SETORIGIN_ENTITIES]; + + Vector m_vecEntities[MAX_SETORIGIN_ENTITIES]; + Vector m_vecOffset; + Vector m_vecAngleOffset; + + bool m_bAngleInvertX; + bool m_bAngleInvertY; + bool m_bAngleInvertZ; + + int m_entityNum; + int m_triggerType; + + string_t m_copyPointer; + + bool m_bUpdateEntities; + bool m_bSetupEntities; +}; + +class CTriggerSetOriginManager +{ +public: + CTriggerSetOriginManager() {} + + void Add(CTriggerSetOrigin *pInstance); + void Remove(CTriggerSetOrigin *pInstance); + void Update(); + + static CTriggerSetOriginManager *getInstance() + { + static CTriggerSetOriginManager *pInstance = new CTriggerSetOriginManager; + return pInstance; + } + +private: + CUtlVector> m_Entities; +}; diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index eeec8eef..c5b47f93 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -3642,6 +3642,13 @@ void EXT_FUNC StartFrame() if (TheTutor) { TheTutor->StartFrame(gpGlobals->time); } + + EndFrame(); +} + +void EndFrame() +{ + CTriggerSetOriginManager::getInstance()->Update(); } void ClientPrecache() diff --git a/regamedll/dlls/client.h b/regamedll/dlls/client.h index 504e84f8..f93a98ea 100644 --- a/regamedll/dlls/client.h +++ b/regamedll/dlls/client.h @@ -164,6 +164,7 @@ void PlayerPostThink(edict_t *pEntity); void ParmsNewLevel(); void ParmsChangeLevel(); void StartFrame(); +void EndFrame(); void ClientPrecache(); const char *GetGameDescription(); void SysEngine_Error(const char *error_string); diff --git a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd index fbeeacfd..f177cdca 100644 --- a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd +++ b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd @@ -2813,3 +2813,63 @@ // added by Dmitrich! - February 21, 2004 ;-) @PointClass color(255 128 0) = info_texlights : "Texture Light Config" [] + +// Set the origin of an entity dynamically +@PointClass base(Targetname, Target) size(-8 -8 -8, 8 8 8) iconsprite("sprites/CS/trigger_setorigin.spr") = trigger_setorigin : "Trigger Set Origin" +[ + spawnflags(flags) = + [ + // Will constantly update position if set. + 1: "Constant" : 0 + + // Trigger_setorigin entity will be removed after firing. + 4: "Set Once" : 0 + + // Save the offset between the Target entity and the Copy pointer, apply offset when updating the Target entity's position + // Requires "Constant" flag + 8: "Lock Offsets" : 0 + + 16: "Copy X Angle" : 0 + 32: "Copy Y Angle" : 0 + 64: "Copy Z Angle" : 0 + + 128: "Copy X Axis" : 1 + 256: "Copy Y Axis" : 1 + 512: "Copy Z Axis" : 1 + + // If you're using the Constant flag, check this box to NOT move the origin of the entity or set the angles initially. + // If you're not using the Constant flag, make sure this isn't enabled or trigger_setorigin won't do anything. + // + // This allows the "Constant" + "offset difference" combination to work as intended from the entity's original location. + // + // You would leave this off if you needed to move the entity to an initial position before having it follow another entity. + // (If this isn't set, trigger_setorigin will move the entity to it's copypointer's origin before doing the offset difference calculation) + 1024: "Skip Initial Set" : 0 + ] + + // The entity we wish to copy coordinates/angles from + copypointer(string) : "Copy Pointer" + + // Manual Offset to copied coordinates + offset(string) : "Position Offset (X Y Z)" : "0 0 0" + + // Applied once on first use + // After first use - Applied if "constant" flag is checked, and for each "Copy [x, y, z] Angle" checked. + angleoffset(string) : "Angle Offset (X Y Z)" : "0 0 0" + + invert_x(choices) : "Invert X Angle" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] + invert_y(choices) : "Invert Y Angle" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] + invert_z(choices) : "Invert Z Angle" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] +] diff --git a/regamedll/extra/Toolkit/GameDefinitionFile/sprites/CS/trigger_setorigin.spr b/regamedll/extra/Toolkit/GameDefinitionFile/sprites/CS/trigger_setorigin.spr new file mode 100644 index 00000000..085b0e65 Binary files /dev/null and b/regamedll/extra/Toolkit/GameDefinitionFile/sprites/CS/trigger_setorigin.spr differ diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj index 45ee9ba4..10a4f133 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj +++ b/regamedll/msvc/ReGameDLL.vcxproj @@ -39,6 +39,7 @@ + @@ -915,6 +916,7 @@ + diff --git a/regamedll/msvc/ReGameDLL.vcxproj.filters b/regamedll/msvc/ReGameDLL.vcxproj.filters index 87e61d81..7dd75f97 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj.filters +++ b/regamedll/msvc/ReGameDLL.vcxproj.filters @@ -75,6 +75,9 @@ {00d15c50-66d7-4210-9239-e8cd8fb9f052} + + {cc40695f-5d17-4ee9-b410-1be65c49c099} + @@ -551,6 +554,9 @@ dlls + + dlls\addons + @@ -1051,6 +1057,9 @@ dlls + + dlls\addons + diff --git a/regamedll/public/regamedll/regamedll_interfaces.h b/regamedll/public/regamedll/regamedll_interfaces.h index 639a0082..d5122418 100644 --- a/regamedll/public/regamedll/regamedll_interfaces.h +++ b/regamedll/public/regamedll/regamedll_interfaces.h @@ -298,6 +298,7 @@ class CCSTriggerChangeTarget: public CCSDelay {}; class CCSTriggerCamera: public CCSDelay {}; class CCSWeather: public CCSTrigger {}; class CCSClientFog: public CCSEntity {}; +class CCSTriggerSetOrigin: public CCSDelay {}; inline CBasePlayer *CCSPlayer::BasePlayer() const { return reinterpret_cast(this->m_pContainingEntity); diff --git a/regamedll/regamedll/dlls.h b/regamedll/regamedll/dlls.h index 5a403397..84a31d62 100644 --- a/regamedll/regamedll/dlls.h +++ b/regamedll/regamedll/dlls.h @@ -131,6 +131,9 @@ typedef float& FloatRef; #include "bot/cs_bot.h" +// Addons +#include "addons/trigger_setorigin.h" + // Tutor #include "tutor.h" #include "tutor_base_states.h"