/* * Copyright (c) 2016-2024 Vera Visions LLC. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ static bool droptofloorwrapper(entity foo) { bool result; entity old_self = self; self = foo; result = droptofloor(); self = old_self; return result; } void NSEntity::NSEntity(void) { identity = 1; m_flSpawnTime = time; m_vecEditorColor = [1,1,1]; } void NSEntity::Spawned(void) { super::Spawned(); m_oldAngle = angles; m_oldOrigin = origin; m_oldModel = Util_FixModel(model); m_oldSolid = solid; #ifdef SERVER m_oldstrTarget = target; if (m_oldModel && m_oldModel != "") { precache_model(GetSpawnModel()); } if (m_strOnTrigger) { m_strOnTrigger = CreateOutput(m_strOnTrigger); } #endif } float NSEntity::EntIndex(void) { return (num_for_edict(this)); } bool NSEntity::DropToFloor(void) { return droptofloorwrapper(this); } vector NSEntity::GetForward(void) { return anglesToForward(angles); } vector NSEntity::GetRight(void) { return anglesToRight(angles); } vector NSEntity::GetUp(void) { return anglesToUp(angles); } vector NSEntity::WorldSpaceCenter(void) { return (absmin + (0.5 * (absmax - absmin))); } float NSEntity::WaterLevel(void) { return (waterlevel); } bool NSEntity::VisibleVec(vector org) { vector flDelta; float flFoV; flDelta = vectorNormalize(org - origin); flFoV = flDelta * GetForward(); if (flFoV > 0.3f) { traceline(origin, org, TRUE, this); if (trace_fraction == 1.0f) { return (true); } } return (false); } bool NSEntity::Visible(entity ent) { /* is it in our field of view? */ if (DistanceFromYaw(ent.origin) > 0.3f) { traceline(origin, ent.origin, MOVE_NORMAL, this); if (trace_fraction == 1.0f || trace_ent == ent) { print(sprintf("%s can see %s\n", classname, ent.classname)); return (true); } } print(sprintf("%s can not see %s\n", classname, ent.classname)); return (false); } float NSEntity::DistanceFromYaw(vector targetPos) { return vectorNormalize(targetPos - origin) * GetForward(); } bool NSEntity::HasSpawnFlags(float sf) { return (spawnflags & sf) ? (true) : (false); } bool NSEntity::IsOnGround(void) { return (flags & FL_ONGROUND) ? (true) : (false); } bool NSEntity::IsSolid(void) { return (solid != SOLID_NOT) ? (true) : (false); } entity NSEntity::GetGroundEntity(void) { return (groundentity); } bool NSEntity::CreatedByMap(void) { return (_mapspawned); } #ifdef CLIENT void NSEntity::RendererRestarted(void) { } void NSEntity::ReceiveEntity(float flNew, float flChanged) { READENTITY_COORD(origin[0], BASEFL_CHANGED_ORIGIN_X) READENTITY_COORD(origin[1], BASEFL_CHANGED_ORIGIN_Y) READENTITY_COORD(origin[2], BASEFL_CHANGED_ORIGIN_Z) READENTITY_ANGLE(angles[0], BASEFL_CHANGED_ANGLES_X) READENTITY_ANGLE(angles[1], BASEFL_CHANGED_ANGLES_Y) READENTITY_ANGLE(angles[2], BASEFL_CHANGED_ANGLES_Z) READENTITY_SHORT(modelindex, BASEFL_CHANGED_MODELINDEX) READENTITY_BYTE(solid, BASEFL_CHANGED_SOLID) READENTITY_BYTE(movetype, BASEFL_CHANGED_FLAGS) READENTITY_INT(flags, BASEFL_CHANGED_FLAGS) READENTITY_INT(vv_flags, BASEFL_CHANGED_FLAGS) READENTITY_COORD(mins[0], BASEFL_CHANGED_SIZE) READENTITY_COORD(mins[1], BASEFL_CHANGED_SIZE) READENTITY_COORD(mins[2], BASEFL_CHANGED_SIZE) READENTITY_COORD(maxs[0], BASEFL_CHANGED_SIZE) READENTITY_COORD(maxs[1], BASEFL_CHANGED_SIZE) READENTITY_COORD(maxs[2], BASEFL_CHANGED_SIZE) READENTITY_BYTE(frame, BASEFL_CHANGED_FRAME) READENTITY_FLOAT(skin, BASEFL_CHANGED_SKIN) READENTITY_FLOAT(effects, BASEFL_CHANGED_EFFECTS) READENTITY_FLOAT(scale, BASEFL_CHANGED_SCALE) READENTITY_COORD(velocity[0], BASEFL_CHANGED_VELOCITY_X) READENTITY_COORD(velocity[1], BASEFL_CHANGED_VELOCITY_Y) READENTITY_COORD(velocity[2], BASEFL_CHANGED_VELOCITY_Z) READENTITY_COORD(avelocity[0], BASEFL_CHANGED_ANGULARVELOCITY) READENTITY_COORD(avelocity[1], BASEFL_CHANGED_ANGULARVELOCITY) READENTITY_COORD(avelocity[2], BASEFL_CHANGED_ANGULARVELOCITY) drawmask = (modelindex != 0) ? MASK_ENGINE : 0; if (scale == 0.0f) scale = 1.0f; if (flChanged & BASEFL_CHANGED_SIZE) setsize(this, mins, maxs); } void NSEntity::postdraw(void) { } #else void NSEntity::DebugDraw(void) { DebugBox(GetOrigin(), GetMins(), GetMaxs(), m_vecEditorColor, 0.75f); } /* Make sure StartFrame calls this */ float NSEntity::SendEntity(entity ePEnt, float flChanged) { if (!modelindex) return (0); if (clienttype(ePEnt) != CLIENTTYPE_REAL) return (0); if (alpha == 0.0f) return (0); WriteByte(MSG_ENTITY, ENT_ENTITY); /* optimisation */ { /* we'll never network these if we aren't moving. */ if (movetype == MOVETYPE_NONE) { flChanged &= ~BASEFL_CHANGED_VELOCITY_X; flChanged &= ~BASEFL_CHANGED_VELOCITY_Y; flChanged &= ~BASEFL_CHANGED_VELOCITY_Z; flChanged &= ~BASEFL_CHANGED_ANGULARVELOCITY; } if (m_bIsBrush == true) { flChanged &= ~BASEFL_CHANGED_FLAGS; flChanged &= ~BASEFL_CHANGED_SCALE; } } /* broadcast how much data is expected to be read */ WriteFloat(MSG_ENTITY, flChanged); SENDENTITY_COORD(origin[0], BASEFL_CHANGED_ORIGIN_X) SENDENTITY_COORD(origin[1], BASEFL_CHANGED_ORIGIN_Y) SENDENTITY_COORD(origin[2], BASEFL_CHANGED_ORIGIN_Z) SENDENTITY_ANGLE(angles[0], BASEFL_CHANGED_ANGLES_X) SENDENTITY_ANGLE(angles[1], BASEFL_CHANGED_ANGLES_Y) SENDENTITY_ANGLE(angles[2], BASEFL_CHANGED_ANGLES_Z) SENDENTITY_SHORT(modelindex, BASEFL_CHANGED_MODELINDEX) SENDENTITY_BYTE(solid, BASEFL_CHANGED_SOLID) SENDENTITY_BYTE(movetype, BASEFL_CHANGED_FLAGS) SENDENTITY_INT(flags, BASEFL_CHANGED_FLAGS) SENDENTITY_INT(vv_flags, BASEFL_CHANGED_FLAGS) SENDENTITY_COORD(mins[0], BASEFL_CHANGED_SIZE) SENDENTITY_COORD(mins[1], BASEFL_CHANGED_SIZE) SENDENTITY_COORD(mins[2], BASEFL_CHANGED_SIZE) SENDENTITY_COORD(maxs[0], BASEFL_CHANGED_SIZE) SENDENTITY_COORD(maxs[1], BASEFL_CHANGED_SIZE) SENDENTITY_COORD(maxs[2], BASEFL_CHANGED_SIZE) SENDENTITY_BYTE(frame, BASEFL_CHANGED_FRAME) SENDENTITY_FLOAT(skin, BASEFL_CHANGED_SKIN) SENDENTITY_FLOAT(effects, BASEFL_CHANGED_EFFECTS) SENDENTITY_FLOAT(scale, BASEFL_CHANGED_SCALE) SENDENTITY_COORD(velocity[0], BASEFL_CHANGED_VELOCITY_X) SENDENTITY_COORD(velocity[1], BASEFL_CHANGED_VELOCITY_Y) SENDENTITY_COORD(velocity[2], BASEFL_CHANGED_VELOCITY_Z) SENDENTITY_COORD(avelocity[0], BASEFL_CHANGED_ANGULARVELOCITY) SENDENTITY_COORD(avelocity[1], BASEFL_CHANGED_ANGULARVELOCITY) SENDENTITY_COORD(avelocity[2], BASEFL_CHANGED_ANGULARVELOCITY) return (1); } void NSEntity::EvaluateEntity(void) { EVALUATE_VECTOR(origin, 0, BASEFL_CHANGED_ORIGIN_X) EVALUATE_VECTOR(origin, 1, BASEFL_CHANGED_ORIGIN_Y) EVALUATE_VECTOR(origin, 2, BASEFL_CHANGED_ORIGIN_Z) EVALUATE_VECTOR(angles, 0, BASEFL_CHANGED_ANGLES_X) EVALUATE_VECTOR(angles, 1, BASEFL_CHANGED_ANGLES_Y) EVALUATE_VECTOR(angles, 2, BASEFL_CHANGED_ANGLES_Z) EVALUATE_FIELD(modelindex, BASEFL_CHANGED_MODELINDEX) EVALUATE_FIELD(solid, BASEFL_CHANGED_SOLID) EVALUATE_FIELD(movetype, BASEFL_CHANGED_FLAGS) EVALUATE_FIELD(flags, BASEFL_CHANGED_FLAGS) EVALUATE_FIELD(vv_flags, BASEFL_CHANGED_FLAGS) EVALUATE_VECTOR(mins, 0, BASEFL_CHANGED_SIZE) EVALUATE_VECTOR(mins, 1, BASEFL_CHANGED_SIZE) EVALUATE_VECTOR(mins, 2, BASEFL_CHANGED_SIZE) EVALUATE_VECTOR(maxs, 0, BASEFL_CHANGED_SIZE) EVALUATE_VECTOR(maxs, 1, BASEFL_CHANGED_SIZE) EVALUATE_VECTOR(maxs, 2, BASEFL_CHANGED_SIZE) EVALUATE_FIELD(frame, BASEFL_CHANGED_FRAME) EVALUATE_FIELD(skin, BASEFL_CHANGED_SKIN) EVALUATE_FIELD(effects, BASEFL_CHANGED_EFFECTS) EVALUATE_FIELD(scale, BASEFL_CHANGED_SCALE) EVALUATE_VECTOR(velocity, 0, BASEFL_CHANGED_VELOCITY_X) EVALUATE_VECTOR(velocity, 1, BASEFL_CHANGED_VELOCITY_Y) EVALUATE_VECTOR(velocity, 2, BASEFL_CHANGED_VELOCITY_Z) EVALUATE_VECTOR(avelocity, 0, BASEFL_CHANGED_ANGULARVELOCITY) EVALUATE_VECTOR(avelocity, 1, BASEFL_CHANGED_ANGULARVELOCITY) EVALUATE_VECTOR(avelocity, 2, BASEFL_CHANGED_ANGULARVELOCITY) } /* Make sure StartFrame calls this */ void NSEntity::ParentUpdate(void) { EvaluateEntity(); frame1time += frametime; /* handle end-touch */ if (m_beingTouched == true) if (m_flTouchTime < GetTime()) { EndTouch(m_eTouchLast); m_beingTouched = false; m_eTouchLast = __NULL__; } } entity NSEntity::GetParent(void) { return tag_entity; } void NSEntity::SetParent(string name) { tag_entity = find(world, ::targetname, m_parent); } void NSEntity::SetParentAttachment(string name) { if (name != "origin") { tag_index = gettagindex(tag_entity, name); } else { tag_index = 0; } } void NSEntity::ClearParent(void) { tag_entity = world; tag_index = 0; } void NSEntity::RestoreAngles(void) { angles = GetSpawnAngles(); } void NSEntity::ClearAngles(void) { angles = [0, 0, 0]; } void NSEntity::ForceNetworkUpdate(void) { SendFlags = -1; } void NSEntity::UseBy(entity ourActivator) { if (PlayerUse) { eActivator = (NSEntity)ourActivator; PlayerUse(); } } #endif void NSEntity::SetEffects(float newEffects) { effects = newEffects; } void NSEntity::SetFrame(float newFrame) { if (newFrame == frame) return; frame = newFrame; frame1time = 0.0f; #ifdef SERVER /* check if an event callback exists */ { int eDefEvents; string ourName; if (modelframecount(modelindex) > 0) { ourName = frametoname(modelindex, frame); } else { return; } eDefEvents = tokenize(m_strModelEventCB); for (int i = 0; i < eDefEvents; i+=3) { string testName = argv(i+0); string testInput = argv(i+1); string testData = argv(i+2); if (ourName == testName) { if (testData != "") Input(this, testInput, testData); else Input(this, testInput, ""); /* no parms passed. */ tokenize(m_strModelEventCB); /* ensure argv() is 'rewound'... */ } } } #endif } void NSEntity::SetSkin(float newSkin) { skin = newSkin; } void NSEntity::SetOwner(entity newOwner) { owner = newOwner; } void NSEntity::SetVelocity(vector vecNew) { velocity = vecNew; } void NSEntity::SetTouch(void ()newTouch) { touch = newTouch; } /* we want to really use those set functions because they'll notify of any * networking related changes. otherwise we'll have to keep track of copies * that get updated every frame */ void NSEntity::SetSendFlags(float flSendFlags) { #ifdef SERVER SendFlags |= flSendFlags; #endif } void NSEntity::SetMovetype(float newMovetype) { movetype = newMovetype; } void NSEntity::SetGravity(float newGrav) { gravity = newGrav; } void NSEntity::SetSolid(float newSolid) { solid = newSolid; } void NSEntity::SetScale(float newScale) { if (newScale == scale) return; scale = newScale; setsize(this, m_vecMins * scale, m_vecMaxs * scale); } void NSEntity::UpdateBounds(void) { vector newMins, newMaxs; float flScale = 1.0f; newMins = m_vecMins; newMaxs = m_vecMaxs; /* avoid useless computation */ if (angles !=[0, 0, 0]) { /* adjust bbox according to rotation */ vector vecCorner[8]; newMins = newMaxs =[0, 0, 0]; for (int i = 0; i < 8; i++) { vecCorner[i][0] = (i & 1) ? m_vecMins[0] : m_vecMaxs[0]; vecCorner[i][1] = (i & 2) ? m_vecMins[1] : m_vecMaxs[1]; vecCorner[i][2] = (i & 4) ? m_vecMins[2] : m_vecMaxs[2]; vecCorner[i] += origin; vecCorner[i] = rotateAroundPoint(vecCorner[i], origin, angles[1]); vecCorner[i] -= origin; if (!(vecCorner[i][0] <= newMaxs[0])) newMaxs[0] = vecCorner[i][0]; if (!(vecCorner[i][1] <= newMaxs[1])) newMaxs[1] = vecCorner[i][1]; if (!(vecCorner[i][2] <= newMaxs[2])) newMaxs[2] = vecCorner[i][2]; if (!(vecCorner[i][0] >= newMins[0])) newMins[0] = vecCorner[i][0]; if (!(vecCorner[i][1] >= newMins[1])) newMins[1] = vecCorner[i][1]; if (!(vecCorner[i][2] >= newMins[2])) newMins[2] = vecCorner[i][2]; } } /* 0.0 is never valid, if you want it to disappear do something else */ if (scale != 0.0) flScale = scale; setsize(this, newMins * flScale, newMaxs * flScale); } void NSEntity::SetAngles(vector newAngles) { angles = newAngles; } void NSEntity::SetAngularVelocity(vector newAvel) { avelocity = newAvel; } void NSEntity::SetSize(vector newMins, vector newMaxs) { float flScale = 1.0f; m_vecMins = newMins; m_vecMaxs = newMaxs; /* 0.0 is never valid, if you want it to disappear do something else */ if (scale != 0.0f) flScale = scale; setsize(this, newMins * flScale, newMaxs * flScale); } void NSEntity::SetOrigin(vector newOrigin) { setorigin(this, newOrigin); } void NSEntity::SetModel(string newModel) { m_bIsBrush = substring(newModel, 0, 1) == "*" ? true : false; model = newModel; setmodel(this, newModel); /* mins/maxs have been updated by setmodel */ SetSize(mins, maxs); } void NSEntity::SetModelindex(float newModelIndex) { if (newModelIndex == modelindex) return; modelindex = newModelIndex; SetSize(mins, maxs); } void NSEntity::AddAngularVelocity(vector addVel) { avelocity += addVel; } void NSEntity::AddVelocity(vector addVel) { velocity += addVel; } void NSEntity::AddEffects(float fl) { effects |= fl; } void NSEntity::RemoveEffects(float fl) { effects &= ~fl; } void NSEntity::AddFlags(float fl) { flags |= fl; } void NSEntity::RemoveFlags(float fl) { flags &= ~fl; } void NSEntity::AddVFlags(float fl) { vv_flags |= fl; } void NSEntity::RemoveVFlags(float fl) { vv_flags &= ~fl; } void NSEntity::TurnTo(float targetAngle) { angles[1] = targetAngle; } void NSEntity::TurnToPos(vector targetPos) { angles = vectorToAngles(targetPos - WorldSpaceCenter()); } void NSEntity::SetThink(void (void) func) { think = func; } void NSEntity::SetNextThink(float fl) { float flTime = GetTime() + fl; /* HACK: to make sure things happen post-spawn */ if (flTime == 0.0f) flTime = 0.001f; if (flTime >= 0) nextthink = flTime; else EntError("%s sets bogus nextthink value %f", classname, flTime); } void NSEntity::ScheduleThink(void (void) func, float fl) { SetThink(func); SetNextThink(fl); } vector NSEntity::GetSpawnOrigin(void) { return (m_oldOrigin); } vector NSEntity::GetSpawnAngles(void) { return (m_oldAngle); } string NSEntity::GetSpawnModel(void) { return (m_oldModel); } float NSEntity::GetEffects(void) { return (effects); } float NSEntity::GetFrame(void) { return (frame); } float NSEntity::GetSkin(void) { return (skin); } float NSEntity::GetScale(void) { return (scale); } entity NSEntity::GetOwner(void) { return (owner); } vector NSEntity::GetVelocity(void) { return (velocity); } float NSEntity::GetSolid(void) { return (solid); } string NSEntity::GetModel(void) { return (model); } float NSEntity::GetModelindex(void) { return (modelindex); } float NSEntity::GetMovetype(void) { return (movetype); } float NSEntity::GetGravity(void) { return (gravity); } vector NSEntity::GetAngles(void) { return (angles); } vector NSEntity::GetAngularVelocity(void) { return (avelocity); } vector NSEntity::GetOrigin(void) { return (origin); } vector NSEntity::GetMins(void) { return (mins); } vector NSEntity::GetMaxs(void) { return (maxs); } vector NSEntity::GetRealMins(void) { return (m_vecMins); } vector NSEntity::GetRealMaxs(void) { return (m_vecMaxs); } vector NSEntity::GetAbsoluteMins(void) { return (absmin); } vector NSEntity::GetAbsoluteMaxs(void) { return (absmax); } float NSEntity::GetFlags(void) { return (flags); } float NSEntity::GetVFlags(void) { return (vv_flags); } bool NSEntity::HasFlags(float bits) { return (flags & bits) ? (true) : (false); } bool NSEntity::HasVFlags(float bits) { return (vv_flags & bits) ? (true) : (false); } float NSEntity::GetNextThinkTime(void) { return (nextthink); } bool NSEntity::IsThinking(void) { return (nextthink > GetTime()) ? (true) : (false); } void NSEntity::ReleaseThink(void) { think = __NULL__; nextthink = 0.0f; } void NSEntity::ThinkBusy(float busyTime) { static void ThinkBusy_Done(void) { /* Guess we're done here... */ } ScheduleThink(ThinkBusy_Done, busyTime); } void NSEntity::ClearVelocity(void) { velocity = avelocity = [0.0f, 0.0f, 0.0f]; } #ifdef SERVER void NSEntity::Respawn(void) { super::Respawn(); SetSolid(m_oldSolid); SetAngles(GetSpawnAngles()); SetOrigin(GetSpawnOrigin()); SetModel(GetSpawnModel()); } void NSEntity::Save(float handle) { super::Save(handle); SaveEntity(handle, "tag_entity", tag_entity); SaveFloat(handle, "tag_index", tag_index); SaveFloat(handle, "pvsflags", pvsflags); SaveBool(handle, "_mapspawned", _mapspawned); SaveFloat(handle, "scale", scale); SaveFloat(handle, "vv_flags", vv_flags); SaveFloat(handle, "friction", friction); SaveVector(handle, "m_vecMins", m_vecMins); SaveVector(handle, "m_vecMaxs", m_vecMaxs); SaveVector(handle, "m_oldOrigin", m_oldOrigin); SaveVector(handle, "m_oldAngle", m_oldAngle); SaveString(handle, "m_oldModel", m_oldModel); SaveFloat(handle, "m_oldSolid", m_oldSolid); SaveFloat(handle, "m_flTouchTime", m_flTouchTime); SaveBool(handle, "m_beingTouched", m_beingTouched); SaveEntity(handle, "m_eTouchLast", m_eTouchLast); SaveVector(handle, "m_vecEditorColor", m_vecEditorColor); } void NSEntity::Restore(string strKey, string strValue) { switch (strKey) { case "tag_entity": tag_entity = ReadEntity(strValue); break; case "tag_index": tag_index = ReadFloat(strValue); break; case "pvsflags": pvsflags = ReadFloat(strValue); break; case "_mapspawned": _mapspawned = ReadBool(strValue); break; case "scale": scale = ReadFloat(strValue); break; case "vv_flags": vv_flags = ReadFloat(strValue); break; case "friction": friction = ReadFloat(strValue); break; case "m_vecMins": m_vecMins = ReadVector(strValue); break; case "m_vecMaxs": m_vecMaxs = ReadVector(strValue); break; case "m_oldOrigin": m_oldOrigin = ReadVector(strValue); break; case "m_oldAngle": m_oldAngle = ReadVector(strValue); break; case "m_oldModel": m_oldModel = ReadString(strValue); break; case "m_oldSolid": m_oldSolid = ReadFloat(strValue); break; case "m_flTouchTime": m_flTouchTime = ReadFloat(strValue); break; case "m_beingTouched": m_beingTouched = ReadBool(strValue); break; case "m_eTouchLast": m_eTouchLast = ReadEntity(strValue); break; case "m_vecEditorColor": m_vecEditorColor = ReadVector(strValue); break; default: super::Restore(strKey, strValue); break; } } void NSEntity::Input(entity eAct, string strInput, string strData) { switch (strInput) { case "Kill": Destroy(); break; case "KillHierarchy": /* this works because ents are basically just entnums */ for (entity e = world; (e = findfloat(e, ::owner, this));) { NSEntity ent = (NSEntity) e; ent.Destroy(); } Destroy(); break; case "SetParent": SetParent(strData); break; case "SetParentAttachment": SetParentAttachment(strData); break; case "ClearParent": ClearParent(); break; case "Use": eActivator = (NSEntity)eAct; if (PlayerUse) PlayerUse(); break; case "SpawnDef": break; case "SpawnProjectileDef": if (EntityDef_HasSpawnClass(strData)) { NSProjectile_SpawnDefAttachment(strData, this, 0); } else { float rangedDmg = Skill_GetDefValue(EntityDef_GetKeyValue(strData, "damage")); TraceAttack_FireBullets(1, origin + view_ofs, rangedDmg, [0.01,0.01], 0); } break; case "StartSoundDef": StartSoundDef(strData, CHAN_VOICE, true); break; case "AddVelocity": vector velAdd = stov(strData); velocity += GetForward() * velAdd[0]; velocity += GetRight() * velAdd[1]; velocity += GetUp() * velAdd[2]; break; case "Shockwave": int c = tokenize(strData); WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, EV_BEAMCYLINDER); WriteCoord(MSG_MULTICAST, origin[0]); WriteCoord(MSG_MULTICAST, origin[1]); WriteCoord(MSG_MULTICAST, origin[2]); WriteCoord(MSG_MULTICAST, angles[0]); WriteCoord(MSG_MULTICAST, stof(argv(1))); WriteCoord(MSG_MULTICAST, angles[2]); WriteShort(MSG_MULTICAST, getmodelindex(argv(0))); WriteByte(MSG_MULTICAST, stof(argv(2))); WriteByte(MSG_MULTICAST, stof(argv(3))); WriteByte(MSG_MULTICAST, stof(argv(4))); WriteByte(MSG_MULTICAST, stof(argv(5))); WriteByte(MSG_MULTICAST, stof(argv(6))); WriteByte(MSG_MULTICAST, stof(argv(7))); WriteByte(MSG_MULTICAST, stof(argv(8))); WriteByte(MSG_MULTICAST, stof(argv(9))); WriteByte(MSG_MULTICAST, stof(argv(10))); WriteByte(MSG_MULTICAST, stof(argv(11))); msg_entity = this; multicast(origin, MULTICAST_PVS); break; case "SetOrigin": SetOrigin(stov(strData)); break; case "SetSpawnOrigin": m_oldOrigin = stov(strData); break; case "SetEditorColor": m_vecEditorColor = ReadVector(strData); break; case "Respawn": Respawn(); break; default: NSTrigger::Input(eAct, strInput, strData); } } #endif void NSEntity::SpawnKey(string strKey, string strValue) { bool tempCheck = false; /* we do re-read a lot of the builtin fields in case we want to set defaults. just in case anybody is wondering. */ switch (strKey) { case "spawnflags": spawnflags = ReadFloat(strValue); break; case "origin": origin = ReadVector(strValue); break; case "model": model = ReadString(strValue); break; case "angles": angles = ReadVector(strValue); break; case "angle": angles[1] = ReadFloat(strValue); break; case "solid": solid = ReadFloat(strValue); break; case "friction": friction = ReadFloat(strValue); break; case "editor_color": m_vecEditorColor = ReadVector(strValue); break; #ifdef SERVER case "health": health = ReadFloat(strValue); break; case "movewith": case "parentname": SetParent(ReadString(strValue)); break; case "ignorepvs": tempCheck = ReadBool(strValue); if (tempCheck == true) pvsflags = PVSF_IGNOREPVS; else pvsflags &= ~PVSF_IGNOREPVS; break; #endif case "editor_mins": case "editor_maxs": case "editor_usage": case "editor_model": case "_minlight": break; default: super::SpawnKey(strKey, strValue); break; } } void NSEntity::OnRemoveEntity(void) { } void NSEntity::Destroy(void) { removed = 1; /* mark this as cleanly removed */ OnRemoveEntity(); customphysics = __NULL__; modelindex = 0; solid = 0; movetype = 0; classname = 0; ScheduleThink(Util_Destroy, 0.0f); } void NSEntity::Show(void) { effects &= ~EF_NODRAW; } void NSEntity::Hide(void) { effects |= EF_NODRAW; } bool NSEntity::IsHidden(void) { return (effects & EF_NODRAW) ? true : false; } void NSEntity::Disappear(void) { modelindex = (0); SetSolid(SOLID_NOT); } void NSEntity::MakeStatic(void) { makestatic(this); } bool NSEntity::CanSpawn(bool clientSide) { return !(clientSide); } bool NSEntity::WithinBounds(entity check) { if not (check.absmin[0] >= absmin[0] && check.absmax[0] <= absmax[0]) return (false); if not (check.absmin[1] >= absmin[1] && check.absmax[1] <= absmax[1]) return (false); if not (check.absmin[2] >= absmin[2] && check.absmax[2] <= absmax[2]) return (false); return (true); } bool NSEntity::IntersectsWith(entity check) { if not (check.origin[0] >= absmin[0] && check.origin[0] <= absmax[0]) return (false); if not (check.origin[1] >= absmin[1] && check.origin[1] <= absmax[1]) return (false); if not (check.origin[2] >= absmin[2] && check.origin[2] <= absmax[2]) return (false); return (true); } bool NSEntity::StartSound(string strSample, float channel, float flags, bool broadcast) { if not (whichpack(strcat("sound/", strSample))) return (false); if (broadcast) { sound(this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_FOLLOW); } else { #ifdef SERVER msg_entity = this; sound(this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_UNICAST | SOUNDFLAG_FOLLOW); msg_entity = __NULL__; #else sound(this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_FOLLOW); #endif } SndEntLog("%s (chan: %d bcast: %d) (%v)", strSample, channel, broadcast, origin); return (true); } bool NSEntity::StartSoundDef(string strSample, float channel, bool broadcast) { SndEntLog("%s (chan: %d bcast: %d)", strSample, channel, broadcast); Sound_Play(this, channel, strSample); return (true); } void NSEntity::StopSound(float channel, bool broadcast) { if (broadcast) { Sound_Stop(this, channel); } else { #ifdef SERVER msg_entity = this; sound(this, channel, "common/null.wav", 1.0f, ATTN_NORM, 100, SOUNDFLAG_UNICAST | SOUNDFLAG_FOLLOW, 0 ); msg_entity = __NULL__; #else Sound_Stop(this, channel); #endif } } vector NSEntity::NearestWallPointForRadius(float radius) { vector vecRadius = [radius, radius, radius]; tracebox(origin, -vecRadius, vecRadius, origin, MOVE_EVERYTHING, this); return (trace_fraction <= 1.0) ? trace_endpos : origin; } void NSEntity::HandleThink(void) { /* support for think/nextthink */ if (think && nextthink > 0.0f) { if (nextthink < time) { nextthink = 0.0f; think(); } } } bool NSEntity::IsFacing(entity target) { vector vecDiff = vectorNormalize(target.origin - origin); return ((vecDiff * GetForward()) > 0) ? true : false; } bool NSEntity::IsFacingPosition(vector targetPos) { vector vecDiff = vectorNormalize(targetPos - origin); return ((vecDiff * GetForward()) > 0) ? true : false; } float NSEntity::GetSpawnAge(void) { return (time - m_flSpawnTime); } float NSEntity::GetSpawnTime(void) { return (m_flSpawnTime); } void NSEntity::Transport(vector new_pos, vector new_ang) { float flSpeed = length(this.GetVelocity()); SetVelocity(anglesToForward(new_ang) * flSpeed); SetOrigin(new_pos); SetAngles(new_ang); #ifdef SERVER if (flags & FL_CLIENT) Client_FixAngle(this, new_ang); #endif } void NSEntity::Relink(void) { setorigin(this, origin); } vector NSEntity::GetNearbySpot(void) { vector testPos; float minDist = maxs[0]; vector fwdDir, rightDir, upDir; fwdDir = anglesToForward([0,0,0]); rightDir = anglesToRight([0,0,0]); upDir = anglesToUp([0,0,0]); /* space in front? */ testPos = GetOrigin() + fwdDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* behind? */ testPos = GetOrigin() - fwdDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* left? */ testPos = GetOrigin() - rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* right? */ testPos = GetOrigin() + rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* front left? */ testPos = GetOrigin() + fwdDir * minDist - rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* front right? */ testPos = GetOrigin() + fwdDir * minDist + rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* back left? */ testPos = GetOrigin() - fwdDir * minDist - rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* back right? */ testPos = GetOrigin() - fwdDir * minDist + rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; return g_vec_null; }