2022-12-17 13:32:43 +01:00
|
|
|
/***
|
2013-08-30 13:34:05 -07:00
|
|
|
*
|
|
|
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
|
|
|
*
|
|
|
|
* This product contains software technology licensed from Id
|
|
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
|
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
|
|
|
* without written permission from Valve LLC.
|
|
|
|
*
|
|
|
|
****/
|
2021-11-28 16:54:48 +01:00
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
2021-11-28 20:40:56 +01:00
|
|
|
#include "monsters.h"
|
2021-11-28 16:54:48 +01:00
|
|
|
#include "saverestore.h"
|
|
|
|
#include "client.h"
|
|
|
|
#include "decals.h"
|
|
|
|
#include "gamerules.h"
|
|
|
|
#include "game.h"
|
2022-09-14 21:15:05 +02:00
|
|
|
#include "pm_shared.h"
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void EntvarsKeyvalue(entvars_t* pev, KeyValueData* pkvd);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 19:11:52 +01:00
|
|
|
void OnFreeEntPrivateData(edict_s* pEdict);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
extern Vector VecBModelOrigin(entvars_t* pevBModel);
|
|
|
|
|
|
|
|
static DLL_FUNCTIONS gFunctionTable =
|
|
|
|
{
|
|
|
|
GameDLLInit, //pfnGameInit
|
|
|
|
DispatchSpawn, //pfnSpawn
|
|
|
|
DispatchThink, //pfnThink
|
|
|
|
DispatchUse, //pfnUse
|
|
|
|
DispatchTouch, //pfnTouch
|
|
|
|
DispatchBlocked, //pfnBlocked
|
|
|
|
DispatchKeyValue, //pfnKeyValue
|
|
|
|
DispatchSave, //pfnSave
|
|
|
|
DispatchRestore, //pfnRestore
|
|
|
|
DispatchObjectCollsionBox, //pfnAbsBox
|
|
|
|
|
|
|
|
SaveWriteFields, //pfnSaveWriteFields
|
|
|
|
SaveReadFields, //pfnSaveReadFields
|
|
|
|
|
|
|
|
SaveGlobalState, //pfnSaveGlobalState
|
|
|
|
RestoreGlobalState, //pfnRestoreGlobalState
|
|
|
|
ResetGlobalState, //pfnResetGlobalState
|
|
|
|
|
|
|
|
ClientConnect, //pfnClientConnect
|
|
|
|
ClientDisconnect, //pfnClientDisconnect
|
|
|
|
ClientKill, //pfnClientKill
|
|
|
|
ClientPutInServer, //pfnClientPutInServer
|
|
|
|
ClientCommand, //pfnClientCommand
|
|
|
|
ClientUserInfoChanged, //pfnClientUserInfoChanged
|
|
|
|
ServerActivate, //pfnServerActivate
|
|
|
|
ServerDeactivate, //pfnServerDeactivate
|
|
|
|
|
|
|
|
PlayerPreThink, //pfnPlayerPreThink
|
|
|
|
PlayerPostThink, //pfnPlayerPostThink
|
|
|
|
|
|
|
|
StartFrame, //pfnStartFrame
|
|
|
|
ParmsNewLevel, //pfnParmsNewLevel
|
|
|
|
ParmsChangeLevel, //pfnParmsChangeLevel
|
|
|
|
|
|
|
|
GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game.
|
|
|
|
PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player.
|
|
|
|
|
|
|
|
SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server
|
|
|
|
SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server
|
|
|
|
SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t)
|
|
|
|
|
|
|
|
Sys_Error, //pfnSys_Error Called when engine has encountered an error
|
|
|
|
|
|
|
|
PM_Move, //pfnPM_Move
|
|
|
|
PM_Init, //pfnPM_Init Server version of player movement initialization
|
|
|
|
PM_FindTextureType, //pfnPM_FindTextureType
|
|
|
|
|
|
|
|
SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client
|
|
|
|
UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client
|
|
|
|
AddToFullPack, //pfnAddToFullPack
|
|
|
|
CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too.
|
|
|
|
RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding
|
|
|
|
GetWeaponData, //pfnGetWeaponData
|
|
|
|
CmdStart, //pfnCmdStart
|
|
|
|
CmdEnd, //pfnCmdEnd
|
|
|
|
ConnectionlessPacket, //pfnConnectionlessPacket
|
|
|
|
GetHullBounds, //pfnGetHullBounds
|
|
|
|
CreateInstancedBaselines, //pfnCreateInstancedBaselines
|
|
|
|
InconsistentFile, //pfnInconsistentFile
|
|
|
|
AllowLagCompensation, //pfnAllowLagCompensation
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-03-05 19:11:52 +01:00
|
|
|
NEW_DLL_FUNCTIONS gNewDLLFunctions =
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
|
|
|
OnFreeEntPrivateData, //pfnOnFreeEntPrivateData
|
2021-11-28 19:04:12 +01:00
|
|
|
GameDLLShutdown,
|
2021-03-05 19:11:52 +01:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
static void SetObjectCollisionBox(entvars_t* pev);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int GetEntityAPI(DLL_FUNCTIONS* pFunctionTable, int interfaceVersion)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!pFunctionTable || interfaceVersion != INTERFACE_VERSION)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
return 0;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
|
2021-11-28 15:32:26 +01:00
|
|
|
return 1;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int GetEntityAPI2(DLL_FUNCTIONS* pFunctionTable, int* interfaceVersion)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!pFunctionTable || *interfaceVersion != INTERFACE_VERSION)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// Tell engine what version we had, so it can figure out who is out of date.
|
|
|
|
*interfaceVersion = INTERFACE_VERSION;
|
2021-11-28 15:32:26 +01:00
|
|
|
return 0;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
|
2021-11-28 15:32:26 +01:00
|
|
|
return 1;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-03-05 19:11:52 +01:00
|
|
|
int GetNewDLLFunctions(NEW_DLL_FUNCTIONS* pFunctionTable, int* interfaceVersion)
|
|
|
|
{
|
|
|
|
if (!pFunctionTable || *interfaceVersion != NEW_DLL_FUNCTIONS_VERSION)
|
|
|
|
{
|
|
|
|
*interfaceVersion = NEW_DLL_FUNCTIONS_VERSION;
|
2021-11-28 15:32:26 +01:00
|
|
|
return 0;
|
2021-03-05 19:11:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(pFunctionTable, &gNewDLLFunctions, sizeof(gNewDLLFunctions));
|
2021-11-28 15:32:26 +01:00
|
|
|
return 1;
|
2021-03-05 19:11:52 +01:00
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int DispatchSpawn(edict_t* pent)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
if (pEntity)
|
|
|
|
{
|
|
|
|
// Initialize these or entities who don't link to the world won't have anything in here
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->pev->absmin = pEntity->pev->origin - Vector(1, 1, 1);
|
|
|
|
pEntity->pev->absmax = pEntity->pev->origin + Vector(1, 1, 1);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
pEntity->Spawn();
|
|
|
|
|
|
|
|
// Try to get the pointer again, in case the spawn function deleted the entity.
|
|
|
|
// UNDONE: Spawn() should really return a code to ask that the entity be deleted, but
|
|
|
|
// that would touch too much code for me to do that right now.
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity = (CBaseEntity*)GET_PRIVATE(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (g_pGameRules && !g_pGameRules->IsAllowedToSpawn(pEntity))
|
|
|
|
return -1; // return that this entity should be deleted
|
|
|
|
if ((pEntity->pev->flags & FL_KILLME) != 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Handle global stuff here
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity && !FStringNull(pEntity->pev->globalname))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
const globalentity_t* pGlobal = gGlobalState.EntityFromTable(pEntity->pev->globalname);
|
|
|
|
if (pGlobal)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// Already dead? delete
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pGlobal->state == GLOBAL_DEAD)
|
2013-08-30 13:34:05 -07:00
|
|
|
return -1;
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (!FStrEq(STRING(gpGlobals->mapname), pGlobal->levelName))
|
|
|
|
pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive
|
|
|
|
// In this level & not dead, continue on as normal
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Spawned entities default to 'On'
|
2021-11-28 16:54:48 +01:00
|
|
|
gGlobalState.EntityAdd(pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON);
|
|
|
|
// ALERT( at_console, "Added global entity %s (%s)\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->globalname) );
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void DispatchKeyValue(edict_t* pentKeyvalue, KeyValueData* pkvd)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!pkvd || !pentKeyvalue)
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
EntvarsKeyvalue(VARS(pentKeyvalue), pkvd);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// If the key was an entity variable, or there's no class set yet, don't look for the object, it may
|
|
|
|
// not exist yet.
|
2021-11-28 16:54:48 +01:00
|
|
|
if (0 != pkvd->fHandled || pkvd->szClassName == NULL)
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Get the actualy entity object
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pentKeyvalue);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!pEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pkvd->fHandled = static_cast<int32>(pEntity->KeyValue(pkvd));
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void DispatchTouch(edict_t* pentTouched, edict_t* pentOther)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (gTouchDisabled)
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pentTouched);
|
|
|
|
CBaseEntity* pOther = (CBaseEntity*)GET_PRIVATE(pentOther);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity && pOther && ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) == 0)
|
|
|
|
pEntity->Touch(pOther);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void DispatchUse(edict_t* pentUsed, edict_t* pentOther)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pentUsed);
|
|
|
|
CBaseEntity* pOther = (CBaseEntity*)GET_PRIVATE(pentOther);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity && (pEntity->pev->flags & FL_KILLME) == 0)
|
|
|
|
pEntity->Use(pOther, pOther, USE_TOGGLE, 0);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void DispatchThink(edict_t* pent)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
if (pEntity)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (FBitSet(pEntity->pev->flags, FL_DORMANT))
|
|
|
|
ALERT(at_error, "Dormant entity %s is thinking!!\n", STRING(pEntity->pev->classname));
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
pEntity->Think();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void DispatchBlocked(edict_t* pentBlocked, edict_t* pentOther)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pentBlocked);
|
|
|
|
CBaseEntity* pOther = (CBaseEntity*)GET_PRIVATE(pentOther);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
if (pEntity)
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->Blocked(pOther);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void DispatchSave(edict_t* pent, SAVERESTOREDATA* pSaveData)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-03-11 17:12:50 +01:00
|
|
|
gpGlobals->time = pSaveData->time;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pent);
|
|
|
|
|
2021-11-29 19:48:37 +01:00
|
|
|
if (pEntity && CSaveRestoreBuffer::IsValidSaveRestoreData(pSaveData))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ENTITYTABLE* pTable = &pSaveData->pTable[pSaveData->currentIndex];
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pTable->pent != pent)
|
|
|
|
ALERT(at_error, "ENTITY TABLE OR INDEX IS WRONG!!!!\n");
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((pEntity->ObjectCaps() & FCAP_DONT_SAVE) != 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
// These don't use ltime & nextthink as times really, but we'll fudge around it.
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity->pev->movetype == MOVETYPE_PUSH)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
float delta = pEntity->pev->nextthink - pEntity->pev->ltime;
|
|
|
|
pEntity->pev->ltime = gpGlobals->time;
|
|
|
|
pEntity->pev->nextthink = pEntity->pev->ltime + delta;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pTable->location = pSaveData->size; // Remember entity position for file I/O
|
|
|
|
pTable->classname = pEntity->pev->classname; // Remember entity class for respawn
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-29 19:48:37 +01:00
|
|
|
CSave saveHelper(*pSaveData);
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->Save(saveHelper);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pTable->size = pSaveData->size - pTable->location; // Size of entity block is data size written to block
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-05 19:11:52 +01:00
|
|
|
void OnFreeEntPrivateData(edict_s* pEdict)
|
|
|
|
{
|
|
|
|
if (pEdict && pEdict->pvPrivateData)
|
|
|
|
{
|
2021-11-20 15:54:00 +01:00
|
|
|
auto entity = reinterpret_cast<CBaseEntity*>(pEdict->pvPrivateData);
|
|
|
|
|
|
|
|
delete entity;
|
|
|
|
|
|
|
|
//Zero this out so the engine doesn't try to free it again.
|
|
|
|
pEdict->pvPrivateData = nullptr;
|
2021-03-05 19:11:52 +01:00
|
|
|
}
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Find the matching global entity. Spit out an error if the designer made entities of
|
|
|
|
// different classes with the same global name
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* FindGlobalEntity(string_t classname, string_t globalname)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
edict_t* pent = FIND_ENTITY_BY_STRING(NULL, "globalname", STRING(globalname));
|
|
|
|
CBaseEntity* pReturn = CBaseEntity::Instance(pent);
|
|
|
|
if (pReturn)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!FClassnameIs(pReturn->pev, STRING(classname)))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_console, "Global entity found %s, wrong class %s\n", STRING(globalname), STRING(pReturn->pev->classname));
|
2013-08-30 13:34:05 -07:00
|
|
|
pReturn = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int DispatchRestore(edict_t* pent, SAVERESTOREDATA* pSaveData, int globalEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-03-11 17:12:50 +01:00
|
|
|
gpGlobals->time = pSaveData->time;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-29 19:48:37 +01:00
|
|
|
if (pEntity && CSaveRestoreBuffer::IsValidSaveRestoreData(pSaveData))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
entvars_t tmpVars;
|
|
|
|
Vector oldOffset;
|
|
|
|
|
2021-11-29 19:48:37 +01:00
|
|
|
CRestore restoreHelper(*pSaveData);
|
2021-11-28 16:54:48 +01:00
|
|
|
if (0 != globalEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 19:48:37 +01:00
|
|
|
CRestore tmpRestore(*pSaveData);
|
2021-11-28 16:54:48 +01:00
|
|
|
tmpRestore.PrecacheMode(false);
|
|
|
|
tmpRestore.ReadEntVars("ENTVARS", &tmpVars);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// HACKHACK - reset the save pointers, we're going to restore for real this time
|
|
|
|
pSaveData->size = pSaveData->pTable[pSaveData->currentIndex].location;
|
|
|
|
pSaveData->pCurrentData = pSaveData->pBaseData + pSaveData->size;
|
|
|
|
// -------------------
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const globalentity_t* pGlobal = gGlobalState.EntityFromTable(tmpVars.globalname);
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
// Don't overlay any instance of the global that isn't the latest
|
|
|
|
// pSaveData->szCurrentMapName is the level this entity is coming from
|
|
|
|
// pGlobla->levelName is the last level the global entity was active in.
|
|
|
|
// If they aren't the same, then this global update is out of date.
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!FStrEq(pSaveData->szCurrentMapName, pGlobal->levelName))
|
2013-08-30 13:34:05 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Compute the new global offset
|
|
|
|
oldOffset = pSaveData->vecLandmarkOffset;
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pNewEntity = FindGlobalEntity(tmpVars.classname, tmpVars.globalname);
|
|
|
|
if (pNewEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// ALERT( at_console, "Overlay %s with %s\n", STRING(pNewEntity->pev->classname), STRING(tmpVars.classname) );
|
2013-08-30 13:34:05 -07:00
|
|
|
// Tell the restore code we're overlaying a global entity from another level
|
2021-11-28 16:54:48 +01:00
|
|
|
restoreHelper.SetGlobalMode(true); // Don't overwrite global fields
|
2013-08-30 13:34:05 -07:00
|
|
|
pSaveData->vecLandmarkOffset = (pSaveData->vecLandmarkOffset - pNewEntity->pev->mins) + tmpVars.mins;
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity = pNewEntity; // we're going to restore this data OVER the old entity
|
|
|
|
pent = ENT(pEntity->pev);
|
2013-08-30 13:34:05 -07:00
|
|
|
// Update the global table to say that the global definition of this entity should come from this level
|
2021-11-28 16:54:48 +01:00
|
|
|
gGlobalState.EntityUpdate(pEntity->pev->globalname, gpGlobals->mapname);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This entity will be freed automatically by the engine. If we don't do a restore on a matching entity (below)
|
|
|
|
// or call EntityUpdate() to move it to this level, we haven't changed global state at all.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((pEntity->ObjectCaps() & FCAP_MUST_SPAWN) != 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->Restore(restoreHelper);
|
2013-08-30 13:34:05 -07:00
|
|
|
pEntity->Spawn();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->Restore(restoreHelper);
|
|
|
|
pEntity->Precache();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Again, could be deleted, get the pointer again.
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity = (CBaseEntity*)GET_PRIVATE(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
#if 0
|
2021-11-28 15:32:26 +01:00
|
|
|
if ( pEntity && !FStringNull(pEntity->pev->globalname) && 0 != globalEntity )
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
ALERT( at_console, "Global %s is %s\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->model) );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Is this an overriding global entity (coming over the transition), or one restoring in a level
|
2021-11-28 16:54:48 +01:00
|
|
|
if (0 != globalEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// ALERT( at_console, "After: %f %f %f %s\n", pEntity->pev->origin.x, pEntity->pev->origin.y, pEntity->pev->origin.z, STRING(pEntity->pev->model) );
|
2013-08-30 13:34:05 -07:00
|
|
|
pSaveData->vecLandmarkOffset = oldOffset;
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetOrigin(pEntity->pev, pEntity->pev->origin);
|
2013-08-30 13:34:05 -07:00
|
|
|
pEntity->OverrideReset();
|
|
|
|
}
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (pEntity && !FStringNull(pEntity->pev->globalname))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
const globalentity_t* pGlobal = gGlobalState.EntityFromTable(pEntity->pev->globalname);
|
|
|
|
if (pGlobal)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// Already dead? delete
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pGlobal->state == GLOBAL_DEAD)
|
2013-08-30 13:34:05 -07:00
|
|
|
return -1;
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (!FStrEq(STRING(gpGlobals->mapname), pGlobal->levelName))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
// In this level & not dead, continue on as normal
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname));
|
2013-08-30 13:34:05 -07:00
|
|
|
// Spawned entities default to 'On'
|
2021-11-28 16:54:48 +01:00
|
|
|
gGlobalState.EntityAdd(pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void DispatchObjectCollsionBox(edict_t* pent)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = (CBaseEntity*)GET_PRIVATE(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
if (pEntity)
|
|
|
|
{
|
|
|
|
pEntity->SetObjectCollisionBox();
|
|
|
|
}
|
|
|
|
else
|
2021-11-28 16:54:48 +01:00
|
|
|
SetObjectCollisionBox(&pent->v);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void SaveWriteFields(SAVERESTOREDATA* pSaveData, const char* pname, void* pBaseData, TYPEDESCRIPTION* pFields, int fieldCount)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 19:48:37 +01:00
|
|
|
if (!CSaveRestoreBuffer::IsValidSaveRestoreData(pSaveData))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CSave saveHelper(*pSaveData);
|
2021-11-28 16:54:48 +01:00
|
|
|
saveHelper.WriteFields(pname, pBaseData, pFields, fieldCount);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void SaveReadFields(SAVERESTOREDATA* pSaveData, const char* pname, void* pBaseData, TYPEDESCRIPTION* pFields, int fieldCount)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 19:48:37 +01:00
|
|
|
if (!CSaveRestoreBuffer::IsValidSaveRestoreData(pSaveData))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-09-14 21:33:34 +02:00
|
|
|
// Always check if the player is stuck when loading a save game.
|
|
|
|
g_CheckForPlayerStuck = true;
|
|
|
|
|
2021-11-29 19:48:37 +01:00
|
|
|
CRestore restoreHelper(*pSaveData);
|
2021-11-28 16:54:48 +01:00
|
|
|
restoreHelper.ReadFields(pname, pBaseData, pFields, fieldCount);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
edict_t* EHANDLE::Get()
|
|
|
|
{
|
2013-08-30 13:34:05 -07:00
|
|
|
if (m_pent)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_pent->serialnumber == m_serialnumber)
|
|
|
|
return m_pent;
|
2013-08-30 13:34:05 -07:00
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
return NULL;
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
edict_t* EHANDLE::Set(edict_t* pent)
|
|
|
|
{
|
|
|
|
m_pent = pent;
|
|
|
|
if (pent)
|
|
|
|
m_serialnumber = m_pent->serialnumber;
|
|
|
|
return pent;
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
EHANDLE::operator CBaseEntity*()
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
|
|
|
return (CBaseEntity*)GET_PRIVATE(Get());
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
CBaseEntity* EHANDLE::operator=(CBaseEntity* pEntity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
if (pEntity)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pent = ENT(pEntity->pev);
|
2013-08-30 13:34:05 -07:00
|
|
|
if (m_pent)
|
|
|
|
m_serialnumber = m_pent->serialnumber;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_pent = NULL;
|
|
|
|
m_serialnumber = 0;
|
|
|
|
}
|
|
|
|
return pEntity;
|
|
|
|
}
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
CBaseEntity* EHANDLE::operator->()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return (CBaseEntity*)GET_PRIVATE(Get());
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// give health
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CBaseEntity::TakeHealth(float flHealth, int bitsDamageType)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
if (0 == pev->takedamage)
|
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// heal
|
|
|
|
if (pev->health >= pev->max_health)
|
2021-11-28 15:32:26 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
pev->health += flHealth;
|
|
|
|
|
|
|
|
if (pev->health > pev->max_health)
|
|
|
|
pev->health = pev->max_health;
|
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CBaseEntity::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
Vector vecTemp;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
if (0 == pev->takedamage)
|
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// UNDONE: some entity types may be immune or resistant to some bitsDamageType
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
// if Attacker == Inflictor, the attack was a melee or other instant-hit attack.
|
2021-11-28 16:54:48 +01:00
|
|
|
// (that is, no actual entity projectile was involved in the attack so use the shooter's origin).
|
|
|
|
if (pevAttacker == pevInflictor)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
vecTemp = pevInflictor->origin - (VecBModelOrigin(pev));
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
// an actual missile was involved.
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
vecTemp = pevInflictor->origin - (VecBModelOrigin(pev));
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// this global is still used for glass and other non-monster killables, along with decals.
|
2013-08-30 13:34:05 -07:00
|
|
|
g_vecAttackDir = vecTemp.Normalize();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// save damage based on the target's armor level
|
|
|
|
|
|
|
|
// figure momentum add (don't let hurt brushes or other triggers move player)
|
|
|
|
if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
|
|
|
|
vecDir = vecDir.Normalize();
|
|
|
|
|
|
|
|
float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5;
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
if (flForce > 1000.0)
|
2013-08-30 13:34:05 -07:00
|
|
|
flForce = 1000.0;
|
|
|
|
pev->velocity = pev->velocity + vecDir * flForce;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// do the damage
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->health -= flDamage;
|
|
|
|
if (pev->health <= 0)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
Killed(pevAttacker, GIB_NORMAL);
|
2021-11-28 15:32:26 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CBaseEntity::Killed(entvars_t* pevAttacker, int iGib)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->takedamage = DAMAGE_NO;
|
|
|
|
pev->deadflag = DEAD_DEAD;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_Remove(this);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* CBaseEntity::GetNextTarget()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (FStringNull(pev->target))
|
2013-08-30 13:34:05 -07:00
|
|
|
return NULL;
|
2021-11-28 16:54:48 +01:00
|
|
|
edict_t* pTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->target));
|
|
|
|
if (FNullEnt(pTarget))
|
2013-08-30 13:34:05 -07:00
|
|
|
return NULL;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
return Instance(pTarget);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Global Savedata for Delay
|
2021-11-28 16:54:48 +01:00
|
|
|
TYPEDESCRIPTION CBaseEntity::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD(CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR),
|
2022-03-28 12:37:15 +02:00
|
|
|
DEFINE_FIELD(CBaseEntity, m_EFlags, FIELD_CHARACTER),
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
DEFINE_FIELD(CBaseEntity, m_pfnThink, FIELD_FUNCTION), // UNDONE: Build table of these!!!
|
|
|
|
DEFINE_FIELD(CBaseEntity, m_pfnTouch, FIELD_FUNCTION),
|
|
|
|
DEFINE_FIELD(CBaseEntity, m_pfnUse, FIELD_FUNCTION),
|
|
|
|
DEFINE_FIELD(CBaseEntity, m_pfnBlocked, FIELD_FUNCTION),
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CBaseEntity::Save(CSave& save)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (save.WriteEntVars("ENTVARS", pev))
|
|
|
|
return save.WriteFields("BASE", this, m_SaveData, ARRAYSIZE(m_SaveData));
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CBaseEntity::Restore(CRestore& restore)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
bool status;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
status = restore.ReadEntVars("ENTVARS", pev);
|
|
|
|
if (status)
|
|
|
|
status = restore.ReadFields("BASE", this, m_SaveData, ARRAYSIZE(m_SaveData));
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->modelindex != 0 && !FStringNull(pev->model))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
Vector mins, maxs;
|
2021-11-28 16:54:48 +01:00
|
|
|
mins = pev->mins; // Set model is about to destroy these
|
2013-08-30 13:34:05 -07:00
|
|
|
maxs = pev->maxs;
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
PRECACHE_MODEL((char*)STRING(pev->model));
|
2013-08-30 13:34:05 -07:00
|
|
|
SET_MODEL(ENT(pev), STRING(pev->model));
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetSize(pev, mins, maxs); // Reset them
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize absmin & absmax to the appropriate box
|
2021-11-28 16:54:48 +01:00
|
|
|
void SetObjectCollisionBox(entvars_t* pev)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((pev->solid == SOLID_BSP) &&
|
|
|
|
(pev->angles != g_vecZero))
|
|
|
|
{ // expand for rotation
|
|
|
|
float max, v;
|
|
|
|
int i;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
max = 0;
|
2021-11-28 16:54:48 +01:00
|
|
|
for (i = 0; i < 3; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
v = fabs(((float*)pev->mins)[i]);
|
2013-08-30 13:34:05 -07:00
|
|
|
if (v > max)
|
|
|
|
max = v;
|
2021-11-28 16:54:48 +01:00
|
|
|
v = fabs(((float*)pev->maxs)[i]);
|
2013-08-30 13:34:05 -07:00
|
|
|
if (v > max)
|
|
|
|
max = v;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
for (i = 0; i < 3; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
((float*)pev->absmin)[i] = ((float*)pev->origin)[i] - max;
|
|
|
|
((float*)pev->absmax)[i] = ((float*)pev->origin)[i] + max;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pev->absmin = pev->origin + pev->mins;
|
|
|
|
pev->absmax = pev->origin + pev->maxs;
|
|
|
|
}
|
|
|
|
|
|
|
|
pev->absmin.x -= 1;
|
|
|
|
pev->absmin.y -= 1;
|
|
|
|
pev->absmin.z -= 1;
|
|
|
|
pev->absmax.x += 1;
|
|
|
|
pev->absmax.y += 1;
|
|
|
|
pev->absmax.z += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CBaseEntity::SetObjectCollisionBox()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
::SetObjectCollisionBox(pev);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CBaseEntity::Intersects(CBaseEntity* pOther)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pOther->pev->absmin.x > pev->absmax.x ||
|
|
|
|
pOther->pev->absmin.y > pev->absmax.y ||
|
|
|
|
pOther->pev->absmin.z > pev->absmax.z ||
|
|
|
|
pOther->pev->absmax.x < pev->absmin.x ||
|
|
|
|
pOther->pev->absmax.y < pev->absmin.y ||
|
|
|
|
pOther->pev->absmax.z < pev->absmin.z)
|
|
|
|
return false;
|
2021-11-28 15:32:26 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CBaseEntity::MakeDormant()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
SetBits(pev->flags, FL_DORMANT);
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
// Don't touch
|
|
|
|
pev->solid = SOLID_NOT;
|
|
|
|
// Don't move
|
|
|
|
pev->movetype = MOVETYPE_NONE;
|
|
|
|
// Don't draw
|
2021-11-28 16:54:48 +01:00
|
|
|
SetBits(pev->effects, EF_NODRAW);
|
2013-08-30 13:34:05 -07:00
|
|
|
// Don't think
|
|
|
|
pev->nextthink = 0;
|
|
|
|
// Relink
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetOrigin(pev, pev->origin);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CBaseEntity::IsDormant()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return FBitSet(pev->flags, FL_DORMANT);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CBaseEntity::IsInWorld()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// position
|
|
|
|
if (pev->origin.x >= 4096)
|
|
|
|
return false;
|
|
|
|
if (pev->origin.y >= 4096)
|
|
|
|
return false;
|
|
|
|
if (pev->origin.z >= 4096)
|
|
|
|
return false;
|
|
|
|
if (pev->origin.x <= -4096)
|
|
|
|
return false;
|
|
|
|
if (pev->origin.y <= -4096)
|
|
|
|
return false;
|
|
|
|
if (pev->origin.z <= -4096)
|
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
// speed
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->velocity.x >= 2000)
|
|
|
|
return false;
|
|
|
|
if (pev->velocity.y >= 2000)
|
|
|
|
return false;
|
|
|
|
if (pev->velocity.z >= 2000)
|
|
|
|
return false;
|
|
|
|
if (pev->velocity.x <= -2000)
|
|
|
|
return false;
|
|
|
|
if (pev->velocity.y <= -2000)
|
|
|
|
return false;
|
|
|
|
if (pev->velocity.z <= -2000)
|
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CBaseEntity::ShouldToggle(USE_TYPE useType, bool currentState)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (useType != USE_TOGGLE && useType != USE_SET)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((currentState && useType == USE_ON) || (!currentState && useType == USE_OFF))
|
2021-11-28 15:32:26 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 15:32:26 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
int CBaseEntity::DamageDecal(int bitsDamageType)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->rendermode == kRenderTransAlpha)
|
2013-08-30 13:34:05 -07:00
|
|
|
return -1;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->rendermode != kRenderNormal)
|
2013-08-30 13:34:05 -07:00
|
|
|
return DECAL_BPROOF1;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
return DECAL_GUNSHOT1 + RANDOM_LONG(0, 4);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: szName must be a pointer to constant memory, e.g. "monster_class" because the entity
|
|
|
|
// will keep a pointer to it after this call.
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* CBaseEntity::Create(const char* szName, const Vector& vecOrigin, const Vector& vecAngles, edict_t* pentOwner)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
edict_t* pent;
|
|
|
|
CBaseEntity* pEntity;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pent = CREATE_NAMED_ENTITY(MAKE_STRING(szName));
|
|
|
|
if (FNullEnt(pent))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_console, "NULL Ent in Create!\n");
|
2013-08-30 13:34:05 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity = Instance(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
pEntity->pev->owner = pentOwner;
|
|
|
|
pEntity->pev->origin = vecOrigin;
|
|
|
|
pEntity->pev->angles = vecAngles;
|
2021-11-28 16:54:48 +01:00
|
|
|
DispatchSpawn(pEntity->edict());
|
2013-08-30 13:34:05 -07:00
|
|
|
return pEntity;
|
|
|
|
}
|