Compare commits

...

6 Commits

Author SHA1 Message Date
Marco Cawthorne 22460c5aa0
BotLib: new commands - 'offset [vector]', 'flipx', 'flipy', 'flipz', 'merge [filename.way]', 'loadpb [podbotwaypoint.pwf]', 'loadrich [jumbot.jrf]', 'loadfb [foxbot.fwp]'
Also make the bots use the soundDef when pressing '+use'.
2023-11-17 18:58:24 -08:00
Marco Cawthorne 8566a9a5a7
Base: build menu with base/src/progs.src as well 2023-11-17 18:55:07 -08:00
Marco Cawthorne 32f9d974bb
New commands: listClientSoundDef, listServerSoundDef
Merge various trigger fields from Source entities into NSTrigger
Rename default player related sounds to the Source Engine style for more parity with Half-Life 2 and later games
Various player physics code fixes, such as being unable to jump higher when pushing against solids and faster noclip speed
2023-11-17 18:54:46 -08:00
Marco Cawthorne bf705a9e31
speaker: now shared between client/server game
NSTalkMonster: Remove game specific PREDISASTER flag from the code, implement GAG instead
New entities: env_cascade_light (wip), logic_achievement, env_instructor_hint (wip)
2023-11-15 09:52:11 -08:00
Marco Cawthorne 4790e9d230
NSItem: Position entity after everything else has spawned, to avoid entity lump ordering messing with droptofloor() calls 2023-11-15 00:14:06 -08:00
Marco Cawthorne 038265dd64
trigger_teleport: Special offset rules for players when choosing their final teleport destination. 2023-11-14 23:45:43 -08:00
50 changed files with 2078 additions and 340 deletions

1
base/src/progs.src Executable file → Normal file
View File

@ -1,2 +1,3 @@
#pragma sourcefile client/progs.src
#pragma sourcefile server/progs.src
#pragma sourcefile menu/progs.src

View File

@ -92,7 +92,7 @@ bot::UseButton(void)
}
bestButton.Trigger(this, TRIG_TOGGLE);
sound(this, CHAN_ITEM, "common/wpn_select.wav", 0.25, ATTN_IDLE);
StartSoundDef("Player.WeaponSelected", CHAN_ITEM, false);
}
void

View File

@ -7,5 +7,6 @@ bot_chat.qc
bot_combat.qc
route.qc
way.qc
way_convert.qc
cmd.qc
#endlist

View File

@ -27,14 +27,14 @@ typedef struct waypoint_s
int m_numNeighbours;
} waypoint_t;
static waypoint_t *g_pWaypoints;
static int g_iWaypoints;
waypoint_t *g_pWaypoints;
int g_iWaypoints;
static int g_waylink_status;
var int g_way1 = -1;
var int g_way2 = -1;
static void
void
Way_WipeWaypoints(void)
{
for (int i = 0; i < g_iWaypoints; i++) {
@ -45,7 +45,7 @@ Way_WipeWaypoints(void)
g_iWaypoints = 0;
}
static void
void
Way_LinkNodes(waypoint_t *wp, waypoint_t *w2)
{
int w2n = w2 - g_pWaypoints;
@ -103,7 +103,7 @@ Way_UnlinkNodes(waypoint_t *wp, waypoint_t *w2)
}
}
static void
void
Way_AutoLink(int wpidx)
{
for (int i = 0i; i < g_iWaypoints; i++) {
@ -518,21 +518,34 @@ Way_SaveFile(string filename)
}
void
Way_ReadFile(string strFile)
Way_ReadFile(string strFile, bool flush)
{
float file = fopen(strFile, FILE_READ);
int startId = 0i;
int offSet = 0i;
filestream file = fopen(strFile, FILE_READ);
if (file < 0) {
print("Way_ReadFile: unable to open ", strFile, "\n");
return;
}
Way_WipeWaypoints();
/* read the number of waypoints */
tokenize(fgets(file));
g_iWaypoints = stoi(argv(0));
g_pWaypoints = memalloc(sizeof(*g_pWaypoints) * g_iWaypoints);
for (int i = 0i; i < g_iWaypoints; i++) {
if (flush) {
Way_WipeWaypoints();
g_iWaypoints = stoi(argv(0));
g_pWaypoints = memalloc(sizeof(*g_pWaypoints) * g_iWaypoints);
} else {
int oldSize = g_iWaypoints;
int newSize = g_iWaypoints + stoi(argv(0));
g_pWaypoints = (waypoint_t *)memrealloc(g_pWaypoints, sizeof(waypoint_t), oldSize, newSize);
g_iWaypoints = newSize;
startId = oldSize;
offSet = oldSize;
}
for (int i = startId; i < g_iWaypoints; i++) {
tokenize(fgets(file));
g_pWaypoints[i].m_vecOrigin[0] = stof(argv(0));
g_pWaypoints[i].m_vecOrigin[1] = stof(argv(1));
@ -543,7 +556,7 @@ Way_ReadFile(string strFile)
for (int j = 0i; j < g_pWaypoints[i].m_numNeighbours; j++) {
tokenize(fgets(file));
g_pWaypoints[i].m_pNeighbour[j].m_iNode = stoi(argv(0));
g_pWaypoints[i].m_pNeighbour[j].m_iNode = offSet + stoi(argv(0));
g_pWaypoints[i].m_pNeighbour[j].m_flCost = stof(argv(1));
g_pWaypoints[i].m_pNeighbour[j].m_iFlags = stoi(argv(2));
}
@ -551,7 +564,6 @@ Way_ReadFile(string strFile)
fclose(file);
}
void
Way_ConnectOne(void)
{
@ -725,6 +737,9 @@ Way_DrawDebugInfo(void)
}
}
void Way_ReadFBFile(string, bool);
void Way_ReadPBFile(string, bool);
void Way_ReadJumbotFile(string, bool);
void
Way_Cmd(void)
{
@ -780,6 +795,25 @@ Way_Cmd(void)
g_pWaypoints[i].m_flRadius = autocvar_nav_radius;
}
break;
case "offset":
for (int i = 0i; i < g_iWaypoints; i++) {
g_pWaypoints[i].m_vecOrigin += stov(argv(2));
}
break;
case "flipx":
for (int i = 0i; i < g_iWaypoints; i++) {
g_pWaypoints[i].m_vecOrigin[0] *= -1;
}
case "flipy":
for (int i = 0i; i < g_iWaypoints; i++) {
g_pWaypoints[i].m_vecOrigin[1] *= -1;
}
break;
case "flipz":
for (int i = 0i; i < g_iWaypoints; i++) {
g_pWaypoints[i].m_vecOrigin[2] *= -1;
}
break;
case "linkjump":
Way_FlagJump();
break;
@ -821,7 +855,19 @@ Way_Cmd(void)
Way_SaveFile(argv(2));
break;
case "load":
Way_ReadFile(argv(2));
Way_ReadFile(argv(2), true);
break;
case "merge":
Way_ReadFile(argv(2), false);
break;
case "loadpb":
Way_ReadPBFile(argv(2), true);
break;
case "loadrich":
Way_ReadJumbotFile(argv(2), true);
break;
case "loadfb":
Way_ReadFBFile(argv(2), true);
break;
}
}

502
src/botlib/way_convert.qc Normal file
View File

@ -0,0 +1,502 @@
/*
* Copyright (c) 2016-2022 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.
*/
typedef struct
{
/* 8 bytes */
int type1;
int type2;
int versionNumber;
int extraFlags;
int numNodes;
/* 32 bytes */
int mapname1;
int mapname2;
int mapname3;
int mapname4;
int mapname5;
int mapname6;
int mapname7;
int mapname8;
} fb_header;
#define FBFL_TEAM1 0x00000001
#define FBFL_TEAM2 0x00000002
#define FBFL_TEAMSPECIFIC 0x00000004
#define FBFL_CROUCH 0x00000008
#define FBFL_LADDER 0x00000010
#define FBFL_LIFT 0x00000020
#define FBFL_WALK 0x00000040
#define FBFL_HEALTH 0x00000080
#define FBFL_ARMOR 0x00000100
#define FBFL_AMMO 0x00000200
#define FBFL_SNIPER 0x00000400
#define FBFL_GOALITEM 0x00000800
#define FBFL_GOAL 0x00001000
#define FBFL_SENTRY 0x00002000
#define FBFL_AIMING 0x00004000
#define FBFL_JUMP 0x00008000
#define FBFL_DETPACKSEAL 0x00010000
#define FBFL_PATHCHECK 0x00020000
#define FBFL_UNUSED1 0x00040000
#define FBFL_UNUSED2 0x00080000
#define FBFL_UNUSED3 0x00100000
#define FBFL_UNUSED4 0x00200000
#define FBFL_UNUSED5 0x00400000
#define ITEM_UNUSED6 0x00800000
#define FBFL_PIPETRAP 0x01000000
#define FBFL_DETPACKCLEAR 0x02000000
#define FBFL_TELEENTER 0x04000000
#define FBFL_CONCJUMP 0x08000000
#define FBFL_SENTRY_180 0x10000000
#define FBFL_DEFEND 0x20000000
#define FBFL_TELEEXIT 0x40000000
#define FBFL_DELETED 0x80000000
int
Way_FBFlagsToNC(int inputFlags)
{
int outFlags = 0i;
if (inputFlags & FBFL_JUMP)
outFlags |= LF_JUMP;
if (inputFlags & FBFL_WALK)
outFlags |= LF_WALK;
if (inputFlags & FBFL_CROUCH)
outFlags |= LF_CROUCH;
if (inputFlags & FBFL_AIMING)
outFlags |= LF_AIM;
if (inputFlags & FBFL_LADDER)
outFlags |= LF_AIM;
return outFlags;
}
/* Reads a FB waypoint file.
These are binary files and contain a lot of type sizes that we don't
have access to in QC. So we cannot just fread() into a struct.
The only flag between nodes is seemingly JUMP (1), however the
individual nodes themselves have defining info flags too including
ones for using buttons and ladders. Ideally we'd want to re-interpret
those into linkflags.
*/
void
Way_ReadFBFile(string strFile, bool flush)
{
int startId = 0i;
int offSet = 0i;
fb_header fbHeader;
int *nodeFlags;
filestream file = fopen(strFile, FILE_READ);
if (file < 0) {
print("Way_ReadFile: unable to open ", strFile, "\n");
return;
}
fread(file, (void*)&fbHeader, sizeof(fb_header));
if (flush) {
Way_WipeWaypoints();
g_iWaypoints = fbHeader.numNodes;
g_pWaypoints = memalloc(sizeof(*g_pWaypoints) * g_iWaypoints);
} else {
int oldSize = g_iWaypoints;
int newSize = g_iWaypoints + fbHeader.numNodes;
g_pWaypoints = (waypoint_t *)memrealloc(g_pWaypoints, sizeof(waypoint_t), oldSize, newSize);
g_iWaypoints = newSize;
startId = oldSize;
offSet = oldSize;
}
print(sprintf("FB Waypoints Version %i, %i nodes\n", fbHeader.versionNumber, fbHeader.numNodes));
nodeFlags = (int *)memalloc(sizeof(int) * fbHeader.numNodes);
/* create the nodes */
for (int i = startId; i < g_iWaypoints; i++) {
int iData = 0i;
float flData = 0.0f;
fread(file, (void*)&nodeFlags[i], 4); /* flags */
fread(file, (void*)&iData, 4); /* script flags, should be 1 byte but it's padded. */
fread(file, (void*)&flData, 4); /* origin x */
g_pWaypoints[i].m_vecOrigin[0] = flData;
fread(file, (void*)&flData, 4); /* origin y */
g_pWaypoints[i].m_vecOrigin[1] = flData;
fread(file, (void*)&flData, 4); /* origin z */
g_pWaypoints[i].m_vecOrigin[2] = flData;
}
/* create the links */
for (int i = startId; i < g_iWaypoints; i++) {
int iData = 0i;
fread(file, (void*)&iData, 2); /* neighbour count */
//print(sprintf("%i neighbours\n", iData));
g_pWaypoints[i].m_numNeighbours = iData;
g_pWaypoints[i].m_pNeighbour = memalloc(sizeof(*g_pWaypoints[i].m_pNeighbour) * g_pWaypoints[i].m_numNeighbours);
for (int j = 0i; j < g_pWaypoints[i].m_numNeighbours; j++) {
fread(file, (void*)&iData, 2); /* neighbour index */
g_pWaypoints[i].m_pNeighbour[j].m_iNode = offSet + iData;
g_pWaypoints[i].m_pNeighbour[j].m_flCost = -1;
g_pWaypoints[i].m_pNeighbour[j].m_iFlags = Way_FBFlagsToNC(nodeFlags[offSet + iData]);
}
}
memfree(nodeFlags);
fclose(file);
}
typedef struct
{
/* 8 bytes */
int type1;
int type2;
int versionNumber;
int numNodes;
/* 32 bytes */
int mapname1;
int mapname2;
int mapname3;
int mapname4;
int mapname5;
int mapname6;
int mapname7;
int mapname8;
/* 32 bytes */
int author1;
int author2;
int author3;
int author4;
int author5;
int author6;
int author7;
int author8;
} pb_header;
#define PBFL_USEBUTTON 0x00000001i
#define PBFL_ELEVATOR 0x00000002i
#define PBFL_CROUCH 0x00000004i
#define PBFL_CROSSING 0x00000008i
#define PBFL_GOAL 0x00000010i
#define PBFL_LADDER 0x00000020i
#define PBFL_RESCUE 0x00000040i
#define PBFL_CAMP 0x00000080i
int
Way_PBFlagsToNC(int inputFlags)
{
int outFlags = 0i;
if (inputFlags & 1)
outFlags |= LF_JUMP;
return outFlags;
}
/* Reads a PB version 5, 6, 7 file.
These are binary files and contain a lot of type sizes that we don't
have access to in QC. So we cannot just fread() into a struct.
The only flag between nodes is seemingly JUMP (1), however the
individual nodes themselves have defining info flags too including
ones for using buttons and ladders. Ideally we'd want to re-interpret
those into linkflags.
*/
void
Way_ReadPBFile(string strFile, bool flush)
{
int startId = 0i;
int offSet = 0i;
pb_header pbHeader;
filestream file = fopen(strFile, FILE_READ);
if (file < 0) {
print("Way_ReadFile: unable to open ", strFile, "\n");
return;
}
fread(file, (void*)&pbHeader, sizeof(pb_header));
if (flush) {
Way_WipeWaypoints();
g_iWaypoints = pbHeader.numNodes;
g_pWaypoints = memalloc(sizeof(*g_pWaypoints) * g_iWaypoints);
} else {
int oldSize = g_iWaypoints;
int newSize = g_iWaypoints + pbHeader.numNodes;
g_pWaypoints = (waypoint_t *)memrealloc(g_pWaypoints, sizeof(waypoint_t), oldSize, newSize);
g_iWaypoints = newSize;
startId = oldSize;
offSet = oldSize;
}
print(sprintf("PB Waypoints Version %i, %i nodes\n", pbHeader.versionNumber, pbHeader.numNodes));
for (int i = startId; i < g_iWaypoints; i++) {
int neighbours = 0i;
int index[8];
float cost[8];
int nFlags[8];
int iData = 0i;
float flData = 0.0f;
/* make them all invalid */
for (int n = 0i; n < 8i; n++) {
index[n] = 65535;
}
if (pbHeader.versionNumber == 7) {
fread(file, (void*)&iData, 4); /* number */
fread(file, (void*)&iData, 4); /* flags */
fread(file, (void*)&flData, 4); /* origin x */
g_pWaypoints[i].m_vecOrigin[0] = flData;
fread(file, (void*)&flData, 4); /* origin y */
g_pWaypoints[i].m_vecOrigin[1] = flData;
fread(file, (void*)&flData, 4); /* origin z */
g_pWaypoints[i].m_vecOrigin[2] = flData;
fread(file, (void*)&flData, 4); /* radius */
g_pWaypoints[i].m_flRadius = flData;
fread(file, (void*)&flData, 4); /* camp start x */
fread(file, (void*)&flData, 4); /* camp start y */
fread(file, (void*)&flData, 4); /* camp end x */
fread(file, (void*)&flData, 4); /* camp end y */
fread(file, (void*)&index[0], 2); /* index 1 */
fread(file, (void*)&index[1], 2); /* index 2 */
fread(file, (void*)&index[2], 2); /* index 3 */
fread(file, (void*)&index[3], 2); /* index 4 */
fread(file, (void*)&index[4], 2); /* index 5 */
fread(file, (void*)&index[5], 2); /* index 6 */
fread(file, (void*)&index[6], 2); /* index 7 */
fread(file, (void*)&index[7], 2); /* index 8 */
fread(file, (void*)&nFlags[0], 2); /* nFlags 1 */
fread(file, (void*)&nFlags[1], 2); /* nFlags 2 */
fread(file, (void*)&nFlags[2], 2); /* nFlags 3 */
fread(file, (void*)&nFlags[3], 2); /* nFlags 4 */
fread(file, (void*)&nFlags[4], 2); /* nFlags 5 */
fread(file, (void*)&nFlags[5], 2); /* nFlags 6 */
fread(file, (void*)&nFlags[6], 2); /* nFlags 7 */
fread(file, (void*)&nFlags[7], 2); /* nFlags 8 */
fread(file, (void*)&flData, 4); /* velocity 1 x */
fread(file, (void*)&flData, 4); /* velocity 1 y */
fread(file, (void*)&flData, 4); /* velocity 1 z */
fread(file, (void*)&flData, 4); /* velocity 2 x */
fread(file, (void*)&flData, 4); /* velocity 2 y */
fread(file, (void*)&flData, 4); /* velocity 2 z */
fread(file, (void*)&flData, 4); /* velocity 3 x */
fread(file, (void*)&flData, 4); /* velocity 3 y */
fread(file, (void*)&flData, 4); /* velocity 3 z */
fread(file, (void*)&flData, 4); /* velocity 4 x */
fread(file, (void*)&flData, 4); /* velocity 4 y */
fread(file, (void*)&flData, 4); /* velocity 4 z */
fread(file, (void*)&flData, 4); /* velocity 5 x */
fread(file, (void*)&flData, 4); /* velocity 5 y */
fread(file, (void*)&flData, 4); /* velocity 5 z */
fread(file, (void*)&flData, 4); /* velocity 6 x */
fread(file, (void*)&flData, 4); /* velocity 6 y */
fread(file, (void*)&flData, 4); /* velocity 6 z */
fread(file, (void*)&flData, 4); /* velocity 7 x */
fread(file, (void*)&flData, 4); /* velocity 7 y */
fread(file, (void*)&flData, 4); /* velocity 7 z */
fread(file, (void*)&flData, 4); /* velocity 8 x */
fread(file, (void*)&flData, 4); /* velocity 8 y */
fread(file, (void*)&flData, 4); /* velocity 8 z */
fread(file, (void*)&iData, 4); /* distance 1 */
cost[0] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 2 */
cost[1] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 3 */
cost[2] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 4 */
cost[3] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 5 */
cost[4] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 6 */
cost[5] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 7 */
cost[6] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 8 */
cost[7] = (float)iData;
fread(file, (void*)&iData, 4); /* pointer */
} else if (pbHeader.versionNumber == 6) {
fread(file, (void*)&iData, 4); /* number */
fread(file, (void*)&iData, 4); /* flags */
fread(file, (void*)&flData, 4); /* origin x */
g_pWaypoints[i].m_vecOrigin[0] = flData;
fread(file, (void*)&flData, 4); /* origin y */
g_pWaypoints[i].m_vecOrigin[1] = flData;
fread(file, (void*)&flData, 4); /* origin z */
g_pWaypoints[i].m_vecOrigin[2] = flData;
fread(file, (void*)&flData, 4); /* radius */
g_pWaypoints[i].m_flRadius = flData;
fread(file, (void*)&flData, 4); /* camp start x */
fread(file, (void*)&flData, 4); /* camp start y */
fread(file, (void*)&flData, 4); /* camp end x */
fread(file, (void*)&flData, 4); /* camp end y */
fread(file, (void*)&index[0], 2); /* index 1 */
fread(file, (void*)&index[1], 2); /* index 2 */
fread(file, (void*)&index[2], 2); /* index 3 */
fread(file, (void*)&index[3], 2); /* index 4 */
fread(file, (void*)&index[4], 2); /* index 5 */
fread(file, (void*)&index[5], 2); /* index 6 */
fread(file, (void*)&index[6], 2); /* index 7 */
fread(file, (void*)&index[7], 2); /* index 8 */
fread(file, (void*)&iData, 4); /* distance 1 */
cost[0] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 2 */
cost[1] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 3 */
cost[2] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 4 */
cost[3] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 5 */
cost[4] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 6 */
cost[5] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 7 */
cost[6] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 8 */
cost[7] = (float)iData;
fread(file, (void*)&iData, 4); /* pointer */
} else if (pbHeader.versionNumber == 5) {
fread(file, (void*)&iData, 4); /* number */
fread(file, (void*)&iData, 4); /* flags */
fread(file, (void*)&flData, 4); /* origin x */
g_pWaypoints[i].m_vecOrigin[0] = flData;
fread(file, (void*)&flData, 4); /* origin y */
g_pWaypoints[i].m_vecOrigin[1] = flData;
fread(file, (void*)&flData, 4); /* origin z */
g_pWaypoints[i].m_vecOrigin[2] = flData;
fread(file, (void*)&flData, 4); /* radius */
g_pWaypoints[i].m_flRadius = flData;
fread(file, (void*)&flData, 4); /* camp start x */
fread(file, (void*)&flData, 4); /* camp start y */
fread(file, (void*)&flData, 4); /* camp end x */
fread(file, (void*)&flData, 4); /* camp end y */
fread(file, (void*)&index[0], 2); /* index 1 */
fread(file, (void*)&index[1], 2); /* index 2 */
fread(file, (void*)&index[2], 2); /* index 3 */
fread(file, (void*)&index[3], 2); /* index 4 */
fread(file, (void*)&iData, 4); /* distance 1 */
cost[0] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 2 */
cost[1] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 3 */
cost[2] = (float)iData;
fread(file, (void*)&iData, 4); /* distance 4 */
cost[3] = (float)iData;
fread(file, (void*)&iData, 4); /* pointer */
}
/* check for valid neighbours */
for (int n = 0i; n < 8i; n++) {
if (index[n] != 65535) /* -1 */
neighbours++;
}
g_pWaypoints[i].m_numNeighbours = neighbours;
g_pWaypoints[i].m_pNeighbour = memalloc(sizeof(*g_pWaypoints[i].m_pNeighbour) * g_pWaypoints[i].m_numNeighbours);
for (int j = 0i; j < g_pWaypoints[i].m_numNeighbours; j++) {
g_pWaypoints[i].m_pNeighbour[j].m_iNode = offSet + index[j];
g_pWaypoints[i].m_pNeighbour[j].m_flCost = cost[j];
g_pWaypoints[i].m_pNeighbour[j].m_iFlags = Way_PBFlagsToNC(nFlags[j]);
}
}
fclose(file);
}
/* Reads a Jumbot file.
Plaintext that's simple to parse, however does not store any node
connections. That's because Jumbot was specific to Half-Life and
the AI was smart enough to know how to navigate using only those
helper points.
We count all lines until we hit the end character '$' and then parse
each line - which contains the info: [id] [flag] ([position])
We then link those in linear order. There's probably better ways of
doing that so that'll be an area of research.
*/
void
Way_ReadJumbotFile(string strFile, bool flush)
{
int startId = 0i;
int offSet = 0i;
int nodeCount = 0i;
string line;
filestream file = fopen(strFile, FILE_READ);
if (file < 0) {
print("Way_ReadFile: unable to open ", strFile, "\n");
return;
}
/* read the number of waypoints */
while ((line = fgets(file))) {
if (line != "$") {
nodeCount++;
}
}
fseek(file, 0);
print(sprintf("Jumpbot Waypoints Version %i, %i nodes\n", 1i, nodeCount));
if (flush) {
Way_WipeWaypoints();
g_iWaypoints = nodeCount;
g_pWaypoints = memalloc(sizeof(*g_pWaypoints) * g_iWaypoints);
} else {
int oldSize = g_iWaypoints;
int newSize = g_iWaypoints + nodeCount;
g_pWaypoints = (waypoint_t *)memrealloc(g_pWaypoints, sizeof(waypoint_t), oldSize, newSize);
g_iWaypoints = newSize;
startId = oldSize;
offSet = oldSize;
}
for (int i = startId; i < g_iWaypoints; i++) {
float length = strlen(argv(5));
line = fgets(file);
tokenize(line);
g_pWaypoints[i].m_vecOrigin[0] = stof(argv(3));
g_pWaypoints[i].m_vecOrigin[1] = stof(argv(4));
g_pWaypoints[i].m_vecOrigin[2] = stof(argv(5));
g_pWaypoints[i].m_flRadius = 32.0f;
if (i > startId) {
Way_LinkNodes(&g_pWaypoints[i], &g_pWaypoints[i-1]);
Way_LinkNodes(&g_pWaypoints[i-1], &g_pWaypoints[i]);
}
}
fclose(file);
}

View File

@ -265,6 +265,12 @@ Cmd_Parse(string sCMD)
case "listParticles":
CMD_ListParticles();
break;
case "listClientSoundDef":
Sound_DebugList();
break;
case "listServerSoundDef":
localcmd("sv listSoundDef\n");
break;
case "cleardecals":
CMD_Cleardecals();
break;
@ -446,6 +452,8 @@ Cmd_Init(void)
registercommand("listSounds");
registercommand("listParticles");
registercommand("listTitles");
registercommand("listClientSoundDef");
registercommand("listServerSoundDef");
registercommand("cleardecals");
registercommand("testLight");

View File

@ -51,6 +51,10 @@ Entity_EntityUpdate(float type, float new)
NSENTITY_READENTITY(NSTalkMonster, new)
self.customphysics = Empty;
break;
case ENT_SPEAKER:
NSENTITY_READENTITY(speaker, new)
self.customphysics = Empty;
break;
case ENT_VEHICLE:
NSENTITY_READENTITY(NSVehicle, new)
break;
@ -122,6 +126,9 @@ Entity_EntityUpdate(float type, float new)
case ENT_FOGCONTROLLER:
NSENTITY_READENTITY(env_fog_controller, new)
break;
case ENT_CASCADELIGHT:
NSENTITY_READENTITY(env_cascade_light, new)
break;
case ENT_PARTSYSTEM:
NSENTITY_READENTITY(info_particle_system, new)
break;
@ -140,6 +147,9 @@ Entity_EntityUpdate(float type, float new)
case ENT_WAYPOINT:
NSENTITY_READENTITY(info_waypoint, new)
break;
case ENT_INSTRUCTOR:
NSENTITY_READENTITY(env_instructor_hint, new)
break;
case ENT_PUSH:
NSENTITY_READENTITY(trigger_push, new)
break;

View File

@ -58,13 +58,6 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
PropData_Init();
DecalGroups_Init();
precache_sound("common/wpn_hudon.wav");
precache_sound("common/wpn_hudoff.wav");
precache_sound("common/wpn_moveselect.wav");
precache_sound("common/wpn_select.wav");
precache_sound("common/null.wav");
/* VGUI */
VGUI_Init();
@ -88,6 +81,12 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
WorldSpawn_Init();
Sound_Precache("Player.DenyWeaponSelection");
Sound_Precache("Player.WeaponSelected");
Sound_Precache("Player.WeaponSelectionMoveSlot");
Sound_Precache("Player.WeaponSelectionOpen");
Sound_Precache("Player.WeaponSelectionClose");
/* end msg */
print("Client game initialized.\n");

View File

@ -165,6 +165,13 @@ EV_TraceDebug(void)
traceRep.angles = endOrg;
}
void
EV_Achievement(void)
{
string eventName = readstring();
NSLog("EV_Achievement: %S", eventName);
}
void
Event_Parse(float type)
{
@ -240,6 +247,9 @@ Event_Parse(float type)
case EV_TRACEDEBUG:
EV_TraceDebug();
break;
case EV_ACHIEVEMENT:
EV_Achievement();
break;
default:
error(sprintf("event id %d not recognized. abort immediately.\n", type));
}

View File

@ -103,12 +103,12 @@ server/trigger_once.qc
server/trigger_multiple.qc
server/trigger_teleport.qc
server/trigger_playerfreeze.qc
server/trigger_monsterjump.qc
server/trigger_relay.qc
server/env_shooter.qc
server/gibshooter.qc
server/env_beverage.qc
server/item_food.qc
server/speaker.qc
server/multi_manager.qc
server/momentarybase.qc
server/momentary_rot_button.qc

View File

@ -30,3 +30,14 @@ If you don't want this entity to have collision, consider using func_detail_illu
# TRIVIA
This entity was introduced in Quake II (1997).
*/
class
func_detail:info_null
{
public:
void func_detail(void);
};
void
func_detail::func_detail(void)
{
}

View File

@ -29,5 +29,16 @@ except that it does not use an entity slot or require custom materials.
If you want this entity to have collision, consider using func_detail.
# TRIVIA
This entity was introduced in Quake II (1997).
This entity was introduced in ericw-tools (2017).
*/
class
func_detail_illusionary:info_null
{
public:
void func_detail_illusionary(void);
};
void
func_detail_illusionary::func_detail_illusionary(void)
{
}

View File

@ -27,3 +27,14 @@ worldspawn upon compile.
# TRIVIA
This entity was introduced in Quake II (1997).
*/
class
func_group:info_null
{
public:
void func_group(void);
};
void
func_group::func_group(void)
{
}

View File

@ -152,7 +152,6 @@ private:
hinttype_t m_hintType;
string m_strHintActivity;
float m_flNodeFOV;
bool m_bStartDisabled;
string m_strHintGroup;
ignorefacing_t m_ignoreFacing;
aistate_t m_minState;
@ -165,7 +164,6 @@ info_hint::info_hint(void)
m_hintType = HINT_NONE;
m_strHintActivity = __NULL__;
m_flNodeFOV = 360;
m_bStartDisabled = false;
m_strHintGroup = __NULL__;
m_ignoreFacing = IGNORE_DEFAULT;
m_minState = AISTATE_IDLE;
@ -179,7 +177,6 @@ info_hint::Save(float handle)
SaveFloat(handle, "m_hintType", m_hintType);
SaveString(handle, "m_strHintActivity", m_strHintActivity);
SaveFloat(handle, "m_flNodeFOV", m_flNodeFOV);
SaveBool(handle, "m_bStartDisabled", m_bStartDisabled);
SaveString(handle, "m_strHintGroup", m_strHintGroup);
SaveFloat(handle, "m_ignoreFacing", m_ignoreFacing);
SaveFloat(handle, "m_minState", m_minState);
@ -199,9 +196,6 @@ info_hint::Restore(string strKey, string strValue)
case "m_flNodeFOV":
m_flNodeFOV = ReadFloat(strValue);
break;
case "m_bStartDisabled":
m_bStartDisabled = ReadFloat(strValue);
break;
case "m_strHintGroup":
m_strHintGroup = ReadString(strValue);
break;

View File

@ -168,9 +168,15 @@ light::SpawnKey(string strKey, string strValue)
case "_cone":
case "_cone2":
case "_sky":
case "pitch":
case "_light":
break;
/* mostly for light_environment */
case "pitch":
angles[0] = ReadFloat(strValue);
break;
case "sunangle":
angles[1] = ReadFloat(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
@ -236,9 +242,22 @@ light::Trigger(entity act, triggermode_t state)
}
CLASSEXPORT(light_spot, light)
CLASSEXPORT(light_environment, light)
class
light_environment:light
{
public:
void light_environment(void);
};
void
light_environment::light_environment(void)
{
}
/*!QUAKED light_surface (0 1 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
Material property modifier related to lighting.
# KEYS

View File

@ -59,73 +59,32 @@ public:
virtual void Respawn(void);
virtual void SpawnKey(string, string);
virtual void Input(entity, string, string);
virtual void Save(float);
virtual void Restore(string, string);
private:
bool m_bStartDisabled;
bool m_bEnabled;
};
void
logic_relay::logic_relay(void)
{
m_bStartDisabled = false;
}
void
logic_relay::Respawn(void)
{
InitPointTrigger();
m_bEnabled = (m_bStartDisabled) ? false : true;
}
void
logic_relay::SpawnKey(string keyName, string setValue)
{
switch (keyName) {
case "StartDisabled":
m_bStartDisabled = ReadBool(setValue);
break;
default:
super::SpawnKey(keyName, setValue);
}
}
void
logic_relay::Save(float handle)
{
super::Save(handle);
SaveBool(handle, "m_bStartDisabled", m_bStartDisabled);
SaveBool(handle, "m_bEnabled", m_bEnabled);
}
void
logic_relay::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_bStartDisabled":
m_bStartDisabled = ReadBool(strValue);
break;
case "m_bEnabled":
m_bEnabled = ReadBool(strValue);
break;
default:
super::Restore(strKey, strValue);
}
}
void
logic_relay::Input(entity activatorEntity, string inputName, string dataField)
{
switch (inputName) {
case "Enable":
m_bEnabled = true;
break;
case "Disable":
m_bEnabled = false;
break;
case "Trigger":
if (m_bEnabled == true) {
/* if we don't allow fast retrigger... */
@ -143,9 +102,6 @@ logic_relay::Input(entity activatorEntity, string inputName, string dataField)
}
}
break;
case "Toggle":
m_bEnabled = (m_bEnabled) ? false : true;
break;
/* TODO: complete this mess */
case "CancelPending":
break;

View File

@ -74,13 +74,11 @@ private:
float m_flRandMins;
float m_flRandMaxs;
float m_flRefireTime;
bool m_bStartDisabled;
bool m_bOscillator;
string m_strOnTimer;
string m_strOnTimerHigh;
string m_strOnTimerLow;
bool m_bEnabled;
entity m_eActivator;
};
@ -91,9 +89,7 @@ logic_timer::logic_timer(void)
m_flRandMins = 0.0f;
m_flRandMaxs = 1.0f;
m_flRefireTime = 0.0;
m_bStartDisabled = false;
m_bOscillator = false;
m_bEnabled = true;
m_eActivator = this;
m_strOnTimer = m_strOnTimerHigh = m_strOnTimerLow = __NULL__;
}
@ -114,9 +110,6 @@ logic_timer::SpawnKey(string keyName, string setValue)
case "RefireTime":
m_flRefireTime = ReadFloat(setValue);
break;
case "StartDisabled":
m_bStartDisabled = ReadBool(setValue);
break;
/* I/O related */
case "OnTimer":
m_strOnTimer = PrepareOutput(m_strOnTimer, setValue);
@ -167,12 +160,10 @@ logic_timer::Save(float handle)
SaveFloat(handle, "m_flRandMins", m_flRandMins);
SaveFloat(handle, "m_flRandMaxs", m_flRandMaxs);
SaveFloat(handle, "m_flRefireTime", m_flRefireTime);
SaveBool(handle, "m_bStartDisabled", m_bStartDisabled);
SaveString(handle, "m_strOnTimer", m_strOnTimer);
SaveString(handle, "m_strOnTimerHigh", m_strOnTimerHigh);
SaveString(handle, "m_strOnTimerLow", m_strOnTimerLow);
SaveBool(handle, "m_bOscillator", m_bOscillator);
SaveBool(handle, "m_bEnabled", m_bEnabled);
SaveEntity(handle, "m_eActivator", m_eActivator);
}
@ -192,9 +183,6 @@ logic_timer::Restore(string strKey, string strValue)
case "m_flRefireTime":
m_flRefireTime = ReadFloat(strValue);
break;
case "m_bStartDisabled":
m_bStartDisabled = ReadBool(strValue);
break;
case "m_strOnTimer":
m_strOnTimer = ReadString(strValue);
break;
@ -207,9 +195,6 @@ logic_timer::Restore(string strKey, string strValue)
case "m_bOscillator":
m_bOscillator = ReadBool(strValue);
break;
case "m_bEnabled":
m_bEnabled = ReadBool(strValue);
break;
case "m_eActivator":
m_eActivator = ReadEntity(strValue);
break;
@ -242,9 +227,6 @@ logic_timer::Input(entity activatorEntity, string inputName, string dataField)
m_bEnabled = true;
TimerSetup(); /* reset timer */
break;
case "Disable":
m_bEnabled = false;
break;
case "Toggle":
m_bEnabled = (m_bEnabled) ? false : true;

View File

@ -88,7 +88,7 @@ prop_physics::Respawn(void)
if (HasSpawnFlags(PHYSPROPSFL_PHYSDEVICE))
Sleep();
//Sleep();
Sleep();
}
#else
class

View File

@ -87,11 +87,3 @@ CLASSEXPORT(func_dustmotes, info_null)
CLASSEXPORT(env_soundscape, info_null)
CLASSEXPORT(env_cubemap, info_null)
CLASSEXPORT(sky_camera, info_null)
void
env_glow(void)
{
if (self.model) {
precache_model(self.model);
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2023 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.
*/
/*!QUAKED trigger_monsterjump (.5 .5 .5) ?
# OVERVIEW
When monsters touch this volume, they will be forced to jump.
# KEYS
- "targetname" : Name
- "target" : Target when triggered.
- "speed" : Speed of the jump.
- "height" : Height of the jump.
# TRIVIA
This entity was introduced in Quake (1996).
*/
class
trigger_monsterjump:NSBrushTrigger
{
public:
void trigger_monsterjump(void);
virtual void Respawn(void);
virtual void Touch(entity);
virtual void Save(float);
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
private:
float m_flSpeed;
float m_flHeight;
};
void
trigger_monsterjump::trigger_monsterjump(void)
{
m_flSpeed = 0.0f;
m_flHeight = 0.0f;
}
void
trigger_monsterjump::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "speed":
m_flSpeed = ReadFloat(strValue);
break;
case "height":
m_flHeight = ReadFloat(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
void
trigger_monsterjump::Save(float handle)
{
super::Save(handle);
SaveFloat(handle, "m_flSpeed", m_flSpeed);
SaveFloat(handle, "m_flHeight", m_flHeight);
}
void
trigger_monsterjump::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_flSpeed":
m_flSpeed = ReadFloat(strValue);
break;
case "m_flHeight":
m_flHeight = ReadFloat(strValue);
break;
default:
super::Restore(strKey, strValue);
}
}
void
trigger_monsterjump::Respawn(void)
{
InitBrushTrigger();
}
void
trigger_monsterjump::Touch(entity touchingEntity)
{
vector targetVelocity = g_vec_null;
if (!touchingEntity.flags & FL_MONSTER) {
return;
}
if (GetMaster(touchingEntity) == false) {
return;
}
NSMonster theMonster = (NSMonster)touchingEntity;
targetVelocity = theMonster.GetForward() * m_flSpeed;
targetVelocity[2] += m_flHeight;
theMonster.SetVelocity(targetVelocity);
}

View File

@ -21,7 +21,7 @@ enumflags
TM_PUSHABLES
};
/*!QUAKED trigger_multiple (.5 .5 .5) ? TM_MONSTERS TM_NOCLIENTS TM_PUSHABLES
/*!QUAKED trigger_multiple (.5 .5 .5) ? CLIENTS NPCS PUSHABLES PHYSICS FRIENDLIES CLIENTSINVEHICLES EVERYTHING x x CLIENTSNOTINVEHICLES DEBRIS NPCSINVEHICLES NOBOTS
# OVERVIEW
A trigger volume which works more than once.
@ -31,16 +31,40 @@ A trigger volume which works more than once.
- "killtarget" : Target to kill when triggered.
- "delay" : Delay until target is triggered.
- "wait" : Time until this entity can trigger again
- "StartDisabled" : Entity will have to be enabled in order to work when set to 1.
# INPUTS
- "Enable" : Enable the entity.
- "Disable" : Disable the entity.
- "Toggle" : Toggles between enabled/disabled states.
# OUTPUTS
- "OnStartTouch": Triggered when something starts touching this volume
- "OnEndTouchAll": Triggered when nothing touched the entity no more
# SPAWNFLAGS
- TF_CLIENTS (1) : Clients can touch it.
- TF_NPCS (2) : NPCs can touch it.
- TF_PUSHABLE (4) : Pushables can touch it.
- TF_PHYSICS (8) : NSPhysicsEntity based classes can touch it.
- TF_FRIENDLIES (16) : Friendly NPCs can touch it.
- TF_CLIENTSINVEHICLES (32) : Clients within vehicles can touch it.
- TF_EVERYTHING (64) : Everything can touch it.
- TF_CLIENTSNOTINVEHICLES (512) : Clients outside vehicles can touch it.
- TF_DEBRIS (1024) : Debris can touch it.
- TF_NPCSINVEHICLES (2048) : NPCs in vehicles can touch it.
- TF_NOBOTS (4096) : Bots are never allowed to touch it.
# SPAWNFLAGS (LEGACY)
These work when 'StartDisabled' is not set in the entity definition.
- TM_MONSTERS (1) : Allow NPCs to activate this entity.
- TM_NOCLIENTS (2) : Don't allow players to activate this entity.
- TM_PUSHABLES (4) : Allow func_pushables to trigger this entity.
# NOTES
If you want an entity like this that can only be used once, see trigger_once.
# TRIVIA
This entity was introduced in Quake (1996).
*/
@ -61,9 +85,6 @@ public:
private:
float m_flWait;
bool m_bStartDisabled;
bool m_bIsModern;
bool m_bEnabled;
/* Input/Output */
string m_strOnStartTouch;
@ -80,8 +101,6 @@ trigger_multiple::trigger_multiple(void)
m_strOnStartTouch =
m_strOnEndTouchAll =
m_strOnTrigger = __NULL__;
m_bIsModern = false;
m_bEnabled = true;
}
void
@ -89,9 +108,6 @@ trigger_multiple::Save(float handle)
{
super::Save(handle);
SaveFloat(handle, "m_flWait", m_flWait);
SaveBool(handle, "m_bStartDisabled", m_bStartDisabled);
SaveBool(handle, "m_bIsModern", m_bIsModern);
SaveBool(handle, "m_bEnabled", m_bEnabled);
SaveString(handle, "m_strOnStartTouch", m_strOnStartTouch);
SaveString(handle, "m_strOnEndTouchAll", m_strOnEndTouchAll);
SaveString(handle, "m_strOnTrigger", m_strOnTrigger);
@ -104,15 +120,6 @@ trigger_multiple::Restore(string strKey, string strValue)
case "m_flWait":
m_flWait = ReadFloat(strValue);
break;
case "m_bStartDisabled":
m_bStartDisabled = ReadBool(strValue);
break;
case "m_bIsModern":
m_bIsModern = ReadBool(strValue);
break;
case "m_bEnabled":
m_bEnabled = ReadBool(strValue);
break;
case "m_strOnStartTouch":
m_strOnStartTouch = ReadString(strValue);
break;
@ -170,22 +177,12 @@ void
trigger_multiple::Respawn(void)
{
InitBrushTrigger();
m_bEnabled = (m_bStartDisabled) ? false : true;
}
void
trigger_multiple::Input(entity entityActivator, string inputName, string dataField)
{
switch (inputName) {
case "Enable":
m_bEnabled = true;
break;
case "Disable":
m_bEnabled = false;
break;
case "Toggle":
m_bEnabled = (m_bEnabled) ? false : true;
break;
case "TouchTest":
Touch(entityActivator);
break;

View File

@ -21,7 +21,7 @@ enumflags
TO_PUSHABLES
};
/*!QUAKED trigger_once (.5 .5 .5) ? TO_MONSTERS TO_NOCLIENTS TO_PUSHABLES
/*!QUAKED trigger_once (.5 .5 .5) ? CLIENTS NPCS PUSHABLES PHYSICS FRIENDLIES CLIENTSINVEHICLES EVERYTHING x x CLIENTSNOTINVEHICLES DEBRIS NPCSINVEHICLES NOBOTS
# OVERVIEW
A trigger volume which works only once.
@ -30,11 +30,35 @@ A trigger volume which works only once.
- "target" : Target when triggered.
- "killtarget" : Target to kill when triggered.
- "delay" : Delay until target is triggered.
- "StartDisabled" : Entity will have to be enabled in order to work when set to 1.
# INPUTS
- "Enable" : Enable the entity.
- "Disable" : Disable the entity.
- "Toggle" : Toggles between enabled/disabled states.
# SPAWNFLAGS
- TO_MONSTERS (1) : Allow NPCs to activate this entity.
- TO_NOCLIENTS (2) : Don't allow players to activate this entity.
- TO_PUSHABLES (4) : Allow func_pushables to trigger this entity.
- TF_CLIENTS (1) : Clients can touch it.
- TF_NPCS (2) : NPCs can touch it.
- TF_PUSHABLE (4) : Pushables can touch it.
- TF_PHYSICS (8) : NSPhysicsEntity based classes can touch it.
- TF_FRIENDLIES (16) : Friendly NPCs can touch it.
- TF_CLIENTSINVEHICLES (32) : Clients within vehicles can touch it.
- TF_EVERYTHING (64) : Everything can touch it.
- TF_CLIENTSNOTINVEHICLES (512) : Clients outside vehicles can touch it.
- TF_DEBRIS (1024) : Debris can touch it.
- TF_NPCSINVEHICLES (2048) : NPCs in vehicles can touch it.
- TF_NOBOTS (4096) : Bots are never allowed to touch it.
# SPAWNFLAGS (LEGACY)
These work when 'StartDisabled' is not set in the entity definition.
- TM_MONSTERS (1) : Allow NPCs to activate this entity.
- TM_NOCLIENTS (2) : Don't allow players to activate this entity.
- TM_PUSHABLES (4) : Allow func_pushables to trigger this entity.
# NOTES
If you want an entity like this that can be used more than once, see trigger_multiple.
# TRIVIA
This entity was introduced in Quake (1996).
@ -55,11 +79,8 @@ public:
virtual void Input(entity, string, string);
private:
bool m_bStartDisabled;
bool m_bEnabled;
string m_strOnStartTouch;
string m_strOnTrigger;
bool m_bIsModern;
};
void
@ -67,9 +88,6 @@ trigger_once::trigger_once(void)
{
m_strOnStartTouch =
m_strOnTrigger = __NULL__;
m_bIsModern = false;
m_bStartDisabled = false;
m_bEnabled = true;
}
void
@ -88,39 +106,26 @@ trigger_once::Respawn(void)
{
InitBrushTrigger();
m_iValue = 0;
m_bEnabled = (m_bStartDisabled) ? false : true;
}
void
trigger_once::Save(float handle)
{
super::Save(handle);
SaveBool(handle, "m_bStartDisabled", m_bStartDisabled);
SaveBool(handle, "m_bEnabled", m_bEnabled);
SaveString(handle, "m_strOnStartTouch", m_strOnStartTouch);
SaveString(handle, "m_strOnTrigger", m_strOnTrigger);
SaveBool(handle, "m_bIsModern", m_bIsModern);
}
void
trigger_once::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_bStartDisabled":
m_bStartDisabled = ReadBool(strValue);
break;
case "m_bEnabled":
m_bEnabled = ReadBool(strValue);
break;
case "m_strOnStartTouch":
m_strOnStartTouch = ReadString(strValue);
break;
case "m_strOnTrigger":
m_strOnTrigger = ReadString(strValue);
break;
case "m_bIsModern":
m_bIsModern = ReadBool(strValue);
break;
default:
super::Restore(strKey, strValue);
}
@ -130,10 +135,6 @@ void
trigger_once::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "StartDisabled":
m_bStartDisabled = ReadBool(strValue);
m_bIsModern = true;
break;
case "OnStartTouch":
m_strOnStartTouch = PrepareOutput(m_strOnStartTouch, strValue);
break;
@ -150,15 +151,6 @@ void
trigger_once::Input(entity entityActivator, string inputName, string dataField)
{
switch (inputName) {
case "Enable":
m_bEnabled = true;
break;
case "Disable":
m_bEnabled = false;
break;
case "Toggle":
m_bEnabled = (m_bEnabled) ? false : true;
break;
case "StartTouch":
StartTouch(entityActivator);
break;

View File

@ -21,7 +21,7 @@ Freezing a player means they're unable to move, they can still look around.
# KEYS
- "targetname" : Name
- "killtarget" : Target to kill when triggered.
- "killtarget" : Target to remove when triggered.
# NOTES
Ideas: Add ability to supress looking around, firing weapons, using items

View File

@ -21,18 +21,26 @@ enumflags
/*!QUAKED trigger_relay (.5 .5 .5) ? TRLY_ONCE
# OVERVIEW
This is an inbetween trigger that forces a desired output state
This is an in-between trigger that forces a desired output state
instead of toggling e.g. a door open.
# KEYS
- "targetname" : Name
- "target" : Target when triggered.
- "killtarget" : Target to kill when triggered.
- "delay" : Delay til the target is triggered.
- "target" : Target to trigger.
- "triggerstate" : Desired state of the triggered entity.
- "delay" : Delay til the target is triggered, in seconds.
- "killtarget" : Target to remove when triggered.
# SPAWNFLAGS
- TRLY_ONCE (1) : Will be removed upon triggering its targets.
- TRLY_ONCE (1) : When set, this entity will be removed upon triggering its targets.
# NOTES
The `triggerstate` key can be one of three things:
- 0: Off
- 1: On
- 2: Toggle
Where 'off' will close entities like func_door, and 'on' will open them.
# TRIVIA
This entity was introduced in Quake (1996).

View File

@ -20,18 +20,46 @@ enumflags
TRIGTELE_NOCLIENTS
};
/*!QUAKED trigger_teleport (.5 .5 .5) ? MONSTERS NOCLIENTS
/*!QUAKED trigger_teleport (.5 .5 .5) ? CLIENTS NPCS PUSHABLES PHYSICS FRIENDLIES CLIENTSINVEHICLES EVERYTHING x x CLIENTSNOTINVEHICLES DEBRIS NPCSINVEHICLES NOBOTS
# OVERVIEW
Teleportation volume. Teleports anything it touches to the position of
any entity set as the "target". Works best with info_teleport_destination.
any entity set as the "target".
# KEYS
- "targetname" : Name
- "target" : Which target to teleport to.
- "snd_teleport" : SoundDef to play on the entity teleporting.
- "snd_teleport_enter" : SoundDef to play on the teleporter entrance.
- "snd_teleport_exit" : SoundDef to play on the teleporter exit.
- "StartDisabled" : Entity will have to be enabled in order to work when set to 1.
# INPUTS
- "Enable" : Enable the entity.
- "Disable" : Disable the entity.
- "Toggle" : Toggles between enabled/disabled states.
# SPAWNFLAGS
- MONSTERS (1) : Allow monsters to use this teleporter.
- NOCLIENTS (2) : Disallow clients from using this teleporter.
- TF_CLIENTS (1) : Clients can touch it.
- TF_NPCS (2) : NPCs can touch it.
- TF_PUSHABLE (4) : Pushables can touch it.
- TF_PHYSICS (8) : NSPhysicsEntity based classes can touch it.
- TF_FRIENDLIES (16) : Friendly NPCs can touch it.
- TF_CLIENTSINVEHICLES (32) : Clients within vehicles can touch it.
- TF_EVERYTHING (64) : Everything can touch it.
- TF_CLIENTSNOTINVEHICLES (512) : Clients outside vehicles can touch it.
- TF_DEBRIS (1024) : Debris can touch it.
- TF_NPCSINVEHICLES (2048) : NPCs in vehicles can touch it.
- TF_NOBOTS (4096) : Bots are never allowed to touch it.
# SPAWNFLAGS (LEGACY)
These work when 'StartDisabled' is not set in the entity definition.
- TM_MONSTERS (1) : Allow NPCs to activate this entity.
- TM_NOCLIENTS (2) : Don't allow players to activate this entity.
- TM_PUSHABLES (4) : Allow func_pushables to trigger this entity.
# NOTES
Works best with info_teleport_destination, but you can in theory use any other point entity as well.
# TRIVIA
This entity was introduced in Quake (1996).
@ -180,16 +208,24 @@ trigger_teleport::Touch(entity eToucher)
entity eTarget = find(world, ::targetname, target);
if (eTarget) {
vector endpos = eTarget.origin + [0,0,16];
vector endpos = eTarget.origin;
float flSpeed = vlen(eToucher.velocity);
makevectors(eTarget.angles);
eToucher.velocity = (v_forward * flSpeed);
eToucher.angles = eTarget.angles;
setorigin_safe(eToucher, endpos);
if (eToucher.flags & FL_CLIENT)
if (eToucher.flags & FL_CLIENT) {
Client_FixAngle(eToucher, eToucher.angles);
/* level designers place destinations where the feet
are going to be, because monsters are mainly set up
to be that way (0 0 0 being ground). players however
have their it at the center of mass, so nudge it a little. */
endpos[2] -= eToucher.mins[2];
}
setorigin_safe(eToucher, endpos);
if (m_sndTeleport) {
Sound_Play(eToucher, CHAN_VOICE, m_sndTeleport);
}
@ -212,8 +248,13 @@ trigger_teleport::Touch(entity eToucher)
}
/*!QUAKED info_teleport_destination (1 0 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
Entity designed to designate a destination for a trigger_teleport.
# KEYS
"targetname" Name
Entity designed to designate a destination for a trigger_teleport.
# TRIVIA
This entity was introduced in Quake (1996).
*/
CLASSEXPORT(info_teleport_destination, info_notnull)

View File

@ -16,21 +16,30 @@
/*!QUAKED trigger_transition (.5 .5 .5) ?
# OVERVIEW
Currently unused. This is meant for defining level transition regions.
Defines level transition regions.
All entities touching this volume would carry across to the next level.
# KEYS
- "targetname" : Name
# NOTES
In order for this entity to work, you have to assign a working info_landmark entity to your trigger_changelevel, and give this entity the same targetname as said landmark.
If you don't assign a transition, no entities will carry over currently. This is not accurate to vanilla behaviour in Half-Life but should mirror what Source does.
In Half-Life, everything as part of the current PVS seems to carry over. This is probably not what you want to ever do, especially in large outdoor maps.
# TRIVIA
This entity was introduced in Half-Life (1998).
*/
class
trigger_transition:NSBrushTrigger
{
public:
void trigger_transition(void);
/* overrides */
virtual void Respawn(void);
nonvirtual void SaveTransition(void);
nonvirtual NSEntity FindCarrierEntity(string);
nonvirtual void LoadTransition(void);

View File

@ -15,12 +15,14 @@ shared/env_glow.qc
shared/env_projectedtexture.qc
shared/env_fog.qc
shared/env_fog_controller.qc
shared/env_cascade_light.qc
shared/env_smoker.qc
shared/env_muzzleflash.qc
//shared/env_fire.qc
shared/env_steam.qc
shared/env_shockwave.qc
shared/light_dynamic.qc
shared/logic_achievement.qc
shared/func_monitor.qc
shared/func_illusionary.qc
shared/func_ladder.qc
@ -31,6 +33,7 @@ shared/trigger_camera.qc
shared/trigger_gravity.qc
shared/info_particle_system.qc
shared/info_waypoint.qc
shared/env_instructor_hint.qc
shared/prop_physics_multiplayer.qc
shared/prop_vehicle_driveable.qc
shared/point_spotlight.qc
@ -39,4 +42,5 @@ shared/func_conveyor.qc
shared/prop_rope.qc
shared/phys_rope.qc
shared/worldspawn.qc
shared/speaker.qc
#endlist

View File

@ -0,0 +1,304 @@
/*
* Copyright (c) 2023 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.
*/
enumflags
{
ENVCASLIGHT_CHANGED_ACTIVE,
ENVCASLIGHT_CHANGED_ANGLE_X,
ENVCASLIGHT_CHANGED_ANGLE_Y,
ENVCASLIGHT_CHANGED_ANGLE_Z,
ENVCASLIGHT_CHANGED_COLOR_X,
ENVCASLIGHT_CHANGED_COLOR_Y,
ENVCASLIGHT_CHANGED_COLOR_Z,
ENVCASLIGHT_CHANGED_DISTANCE,
};
/*!QUAKED env_cascade_light (1 .5 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
Shadowmapped outdoor lighting entity.
![Shadows cast by an env_cascade_light](@ref Documentation/Entities/env_cascade_light.png)
# KEYS
- "targetname" : Name
- "color" : Color of the sun light. Three space separated 0-255 based values.
- "maxshadowdistance" : Maximum shadow distance from the camera.
- "uselightenvangles" : When set to 1, the angles are taken from the light_environment in the map.
- "StartDisabled" : Entity will have to be enabled in order to work when set to 1.
# INPUTS
- "SetAngles" : Sets the light angle.
- "LightColor" : Sets the light color. Three space separated 0-255 based values.
- "Enable" : Enable the entity.
- "Disable" : Disable the entity.
- "Toggle" : Toggles between enabled/disabled states.
# TRIVIA
This entity was introduced in Counter-Strike: Global Offensive (2012).
*/
class
env_cascade_light:NSPointTrigger
{
public:
void env_cascade_light(void);
#ifdef SERVER
virtual float SendEntity(entity,float);
virtual void EvaluateEntity(void);
virtual void Trigger(entity, triggermode_t);
virtual void Respawn(void);
virtual void Save(float);
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
virtual void Input(entity, string, string);
#endif
#ifdef CLIENT
virtual void OnRemoveEntity(void);
virtual void ReceiveEntity(float,float);
virtual void RendererRestarted(void);
#endif
private:
NETWORKED_BOOL(m_bLightActive)
NETWORKED_VECTOR(m_vecLightColor)
NETWORKED_FLOAT(m_flShadowDistance)
#ifdef CLIENT
float m_lightHandle;
#else
bool m_bUseEnvAngles;
#endif
};
void
env_cascade_light::env_cascade_light(void)
{
#ifdef SERVER
m_vecLightColor = [1.0, 1.0, 1.0];
m_bLightActive = true;
m_flShadowDistance = 512.0f;
#endif
}
#ifdef SERVER
void
env_cascade_light::SpawnKey(string keyName, string setValue)
{
switch (keyName) {
case "color":
m_vecLightColor = ReadVector(setValue) / 255;
break;
case "maxshadowdistance":
m_flShadowDistance = ReadFloat(setValue);
break;
case "uselightenvangles":
m_bUseEnvAngles = ReadBool(setValue);
break;
case "StartDisabled":
m_bLightActive = ReadBool(setValue) == true ? false : true;
break;
default:
super::SpawnKey(keyName, setValue);
}
}
void
env_cascade_light::Respawn(void)
{
InitPointTrigger();
pvsflags = PVSF_IGNOREPVS;
}
void
env_cascade_light::Save(float handle)
{
super::Save(handle);
SaveBool(handle, "m_bLightActive", m_bLightActive);
SaveVector(handle, "m_vecLightColor", m_vecLightColor);
SaveFloat(handle, "m_flShadowDistance", m_flShadowDistance);
SaveBool(handle, "m_bUseEnvAngles", m_bUseEnvAngles);
}
void
env_cascade_light::Restore(string keyName, string setValue)
{
switch (keyName) {
case "m_bLightActive":
m_bLightActive = ReadBool(setValue);
break;
case "m_vecLightColor":
m_vecLightColor = ReadVector(setValue);
break;
case "m_flShadowDistance":
m_flShadowDistance = ReadFloat(setValue);
break;
case "m_bUseEnvAngles":
m_bUseEnvAngles = ReadBool(setValue);
break;
default:
super::Restore(keyName, setValue);
}
}
void
env_cascade_light::Input(entity activatingEntity, string keyName, string setValue)
{
switch (keyName) {
case "Enable":
m_bLightActive = false;
break;
case "Disable":
m_bLightActive = true;
break;
case "Toggle":
m_bLightActive = !m_bLightActive;
break;
case "SetAngles":
angles = stov(setValue);
break;
case "LightColor":
m_vecLightColor = stov(setValue) / 255;
break;
default:
super::Input(activatingEntity, keyName, setValue);
}
}
void
env_cascade_light::Trigger(entity activatingEntity, triggermode_t triggerState)
{
switch (triggerState) {
case TRIG_OFF:
m_bLightActive = (false);
break;
case TRIG_ON:
m_bLightActive = (true);
break;
default:
m_bLightActive = (true - m_bLightActive);
}
}
void
env_cascade_light::EvaluateEntity(void)
{
if (m_bUseEnvAngles == true) {
light envLight = (light)find(world, ::classname, "light_environment");
if (!envLight) {
error("env_cascade_light unable to find light_environment.\n");
return;
}
makevectors(envLight.GetAngles());
angles = vectoangles(v_forward * -1);
}
//angles[0] = sin(time) * 180.0f;
//angles[1] = sin(time*2) * 180.0f;
EVALUATE_FIELD(m_bLightActive, ENVCASLIGHT_CHANGED_ACTIVE)
EVALUATE_VECTOR(angles, 0, ENVCASLIGHT_CHANGED_ANGLE_X)
EVALUATE_VECTOR(angles, 1, ENVCASLIGHT_CHANGED_ANGLE_Y)
EVALUATE_VECTOR(angles, 2, ENVCASLIGHT_CHANGED_ANGLE_Z)
EVALUATE_VECTOR(m_vecLightColor, 0, ENVCASLIGHT_CHANGED_COLOR_X)
EVALUATE_VECTOR(m_vecLightColor, 1, ENVCASLIGHT_CHANGED_COLOR_Y)
EVALUATE_VECTOR(m_vecLightColor, 2, ENVCASLIGHT_CHANGED_COLOR_Z)
EVALUATE_FIELD(m_flShadowDistance, ENVCASLIGHT_CHANGED_DISTANCE)
}
float
env_cascade_light::SendEntity(entity ePVEnt, float flChanged)
{
if (m_bLightActive == false)
return (0);
WriteByte(MSG_ENTITY, ENT_CASCADELIGHT);
WriteFloat(MSG_ENTITY, flChanged);
SENDENTITY_BYTE(m_bLightActive, ENVCASLIGHT_CHANGED_ACTIVE)
SENDENTITY_COORD(angles[0], ENVCASLIGHT_CHANGED_ANGLE_X)
SENDENTITY_COORD(angles[1], ENVCASLIGHT_CHANGED_ANGLE_Y)
SENDENTITY_COORD(angles[2], ENVCASLIGHT_CHANGED_ANGLE_Z)
SENDENTITY_COLOR(m_vecLightColor[0], ENVCASLIGHT_CHANGED_COLOR_X)
SENDENTITY_COLOR(m_vecLightColor[1], ENVCASLIGHT_CHANGED_COLOR_Y)
SENDENTITY_COLOR(m_vecLightColor[2], ENVCASLIGHT_CHANGED_COLOR_Z)
SENDENTITY_FLOAT(m_flShadowDistance, ENVCASLIGHT_CHANGED_DISTANCE)
return (1);
}
#else
void
env_cascade_light::OnRemoveEntity(void)
{
/* this tells the engine to re-use this for a later light */
dynamiclight_set(m_lightHandle, LFIELD_RADIUS, 0);
m_lightHandle = 0;
}
void
env_cascade_light::LightChanged(float flFlags)
{
bool updateAngle = false;
bool updateColor = false;
updateAngle |= (flFlags & ENVCASLIGHT_CHANGED_ANGLE_X) ? true : false;
updateAngle |= (flFlags & ENVCASLIGHT_CHANGED_ANGLE_Y) ? true : false;
updateAngle |= (flFlags & ENVCASLIGHT_CHANGED_ANGLE_Z) ? true : false;
updateColor |= (flFlags & ENVCASLIGHT_CHANGED_COLOR_X) ? true : false;
updateColor |= (flFlags & ENVCASLIGHT_CHANGED_COLOR_Y) ? true : false;
updateColor |= (flFlags & ENVCASLIGHT_CHANGED_COLOR_Z) ? true : false;
if (updateAngle) {
dynamiclight_set(m_lightHandle, LFIELD_ANGLES, angles);
}
if (updateColor) {
dynamiclight_set(m_lightHandle, LFIELD_COLOUR, m_vecLightColor);
}
}
void
env_cascade_light::ReceiveEntity(float flNew, float flChanged)
{
READENTITY_BYTE(m_bLightActive, ENVCASLIGHT_CHANGED_ACTIVE)
READENTITY_COORD(angles[0], ENVCASLIGHT_CHANGED_ANGLE_X)
READENTITY_COORD(angles[1], ENVCASLIGHT_CHANGED_ANGLE_Y)
READENTITY_COORD(angles[2], ENVCASLIGHT_CHANGED_ANGLE_Z)
READENTITY_COLOR(m_vecLightColor[0], ENVCASLIGHT_CHANGED_COLOR_X)
READENTITY_COLOR(m_vecLightColor[1], ENVCASLIGHT_CHANGED_COLOR_Y)
READENTITY_COLOR(m_vecLightColor[2], ENVCASLIGHT_CHANGED_COLOR_Z)
READENTITY_FLOAT(m_flShadowDistance, ENVCASLIGHT_CHANGED_DISTANCE)
if (flNew) {
RendererRestarted();
} else {
LightChanged(flChanged);
}
}
void
env_cascade_light::RendererRestarted(void)
{
OnRemoveEntity();
m_lightHandle = dynamiclight_spawnstatic(origin, m_flShadowDistance, m_vecLightColor);
dynamiclight_set(m_lightHandle, LFIELD_FLAGS, LFLAG_ORTHOSUN | LFLAG_SHADOWMAP | LFLAG_REALTIMEMODE);
LightChanged(0xFFFFFF);
}
#endif

View File

@ -33,11 +33,13 @@ enumflags
enumflags
{
FUNNEL_REVERSE,
FUNNEL_REPEATABLE
};
/*!QUAKED env_funnel (1 .5 0) (-8 -8 -8) (8 8 8) REVERSE
/*!QUAKED env_funnel (1 .5 0) (-8 -8 -8) (8 8 8) REVERSE REPEATABLE
# OVERVIEW
Controllable beam effect, akin to lightning. Also known as env_lightning.
An effect that when triggered, will create lots of glowing orbs that funnel into
the position of this entity.
# KEYS
- "targetname" : Name

View File

@ -0,0 +1,365 @@
/*
* Copyright (c) 2023 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.
*/
enumflags
{
ENVINSTRUCTOR_CHANGED_ORIGIN,
ENVINSTRUCTOR_CHANGED_IMAGE,
ENVINSTRUCTOR_CHANGED_IMAGE_OFF,
ENVINSTRUCTOR_CHANGED_TEXT,
ENVINSTRUCTOR_CHANGED_TEXT_COLOR,
ENVINSTRUCTOR_CHANGED_TIMEOUT,
ENVINSTRUCTOR_CHANGED_OFFSET,
ENVINSTRUCTOR_CHANGED_STATE
};
/*!QUAKED env_instructor_hint (0 1 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
Used to display hints throughout the environment.
# KEYS
- "targetname" : Name
- "hint_caption" : Text of your hint.
- "hint_color" : Color tint of your text.
- "hint_icon_onscreen" : Icon to use when the hint is visible.
- "hint_icon_offscreen" : Icon to use when the hint is out of view.
- "hint_binding" : Name of the command that we'll display a key/button for.
- "hint_nooffscreen" : When 1, will not show an off-screen hint at all.
- "hint_target" : Hint will be displayed at the named entity.
- "hint_static" : When 0, follows the entity specified in `hint_target`. Will be displayed on the heads-up-display otherwise.
- "hint_allow_nodraw_target" : When 0, will stop rendering if the `hint_target` becomes invisible.
- "hint_forcecaption" : When 1, will show the hint even if it's obscured by a wall.
- "hint_icon_offset" : Height offset at which the hint will be displayed in-world.
- "hint_pulseoption" : Speed at which the icon pulses in size. 0 is none, 3 is very fast.
- "hint_alphaoption" : Speed at which the icon pulses in transparency. 0 is none, 3 is very fast.
- "hint_shakeoption" : Strength at which the icon shakes. 0 is none, 2 is wide.
- "hint_timeout" : Time until the hint stops showing. When 0, needs to be triggered to be disabled.
- "hint_range" : Visible range of the hint in world units.
- "hint_auto_start" : When set to 0, the entity no longer has to be triggered to show, line-of-sight will be enough.
- "hint_display_limit" : Number of times this hint can be shown.
# INPUTS
- "Enable" : Enable the entity.
- "Disable" : Disable the entity.
- "Toggle" : Toggles between enabled/disabled states.
# TRIVIA
This entity was introduced in Left 4 Dead 2 (2009).
*/
class
env_instructor_hint:NSPointTrigger
{
public:
void env_instructor_hint(void);
#ifdef SERVER
virtual void Respawn(void);
virtual void SpawnKey(string,string);
virtual void Save(float);
virtual void Restore(string,string);
virtual void Input(entity,string,string);
virtual void Trigger(entity, triggermode_t);
virtual void EvaluateEntity(void);
virtual float SendEntity(entity,float);
#endif
#ifdef CLIENT
virtual void ReceiveEntity(float, float);
virtual void postdraw(void);
#endif
private:
PREDICTED_STRING(m_strIcon)
PREDICTED_STRING(m_strIconOff)
PREDICTED_STRING(m_strText)
PREDICTED_VECTOR(m_vecTextColor)
PREDICTED_BOOL(m_bEnabled)
NETWORKED_FLOAT(m_flTimeOut)
NETWORKED_FLOAT(m_flOffset)
#ifdef CLIENT
bool m_bOldHintState;
float m_flHintTime;
#endif
};
void
env_instructor_hint::env_instructor_hint(void)
{
m_strIcon =
m_strIconOff =
m_strText = __NULL__;
m_vecTextColor = [1,1,1];
m_flTimeOut = 0.0f;
m_flOffset = 0.0f;
}
#ifdef SERVER
void
env_instructor_hint::Respawn(void)
{
InitPointTrigger();
m_bEnabled = false;
}
void
env_instructor_hint::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "hint_icon_onscreen":
m_strIcon = strValue;
break;
case "hint_icon_offscreen":
m_strIconOff = strValue;
break;
case "hint_caption":
m_strText = strValue;
break;
case "hint_color":
m_vecTextColor = ReadVector(strValue) / 255;
break;
case "hint_timeout":
m_flTimeOut = ReadFloat(strValue);
break;
case "hint_icon_offset":
m_flOffset = ReadFloat(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
void
env_instructor_hint::Save(float handle)
{
super::Save(handle);
SaveString(handle, "m_strIcon", m_strIcon);
SaveString(handle, "m_strIconOff", m_strIconOff);
SaveString(handle, "m_strText", m_strText);
SaveVector(handle, "m_vecTextColor", m_vecTextColor);
SaveFloat(handle, "m_flTimeOut", m_flTimeOut);
SaveFloat(handle, "m_flOffset", m_flOffset);
}
void
env_instructor_hint::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_strIcon":
m_strIcon = ReadString(strValue);
break;
case "m_strIconOff":
m_strIconOff = ReadString(strValue);
break;
case "m_strText":
m_strText = ReadString(strValue);
break;
case "m_vecTextColor":
m_vecTextColor = ReadVector(strValue);
break;
case "m_flTimeOut":
m_flTimeOut = ReadFloat(strValue);
break;
case "m_flOffset":
m_flOffset = ReadFloat(strValue);
break;
default:
super::Restore(strKey, strValue);
}
}
void
env_instructor_hint::Trigger(entity act, triggermode_t state)
{
switch (state) {
case TRIG_OFF:
m_bEnabled = false;
break;
case TRIG_ON:
m_bEnabled = true;
break;
default:
m_bEnabled = m_bEnabled ? false : true;
}
}
void
env_instructor_hint::Input(entity eAct, string strInput, string strData)
{
switch (strInput) {
case "Enable":
Trigger(eAct, TRIG_ON);
break;
case "Disable":
Trigger(eAct, TRIG_OFF);
break;
case "Toggle":
Trigger(eAct, TRIG_TOGGLE);
break;
default:
super::Input(eAct, strInput, strData);
}
}
void
env_instructor_hint::EvaluateEntity(void)
{
EVALUATE_VECTOR(origin, 0, ENVINSTRUCTOR_CHANGED_ORIGIN)
EVALUATE_VECTOR(origin, 1, ENVINSTRUCTOR_CHANGED_ORIGIN)
EVALUATE_VECTOR(origin, 2, ENVINSTRUCTOR_CHANGED_ORIGIN)
EVALUATE_FIELD(m_strIcon, ENVINSTRUCTOR_CHANGED_IMAGE)
EVALUATE_FIELD(m_strIconOff, ENVINSTRUCTOR_CHANGED_IMAGE_OFF)
EVALUATE_FIELD(m_strText, ENVINSTRUCTOR_CHANGED_TEXT)
EVALUATE_VECTOR(m_vecTextColor, 0, ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
EVALUATE_VECTOR(m_vecTextColor, 1, ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
EVALUATE_VECTOR(m_vecTextColor, 2, ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
EVALUATE_FIELD(m_flTimeOut, ENVINSTRUCTOR_CHANGED_TIMEOUT)
EVALUATE_FIELD(m_flOffset, ENVINSTRUCTOR_CHANGED_OFFSET)
EVALUATE_FIELD(m_bEnabled, ENVINSTRUCTOR_CHANGED_STATE)
pvsflags = PVSF_IGNOREPVS;
}
float
env_instructor_hint::SendEntity(entity ePEnt, float flChanged)
{
WriteByte(MSG_ENTITY, ENT_INSTRUCTOR);
WriteFloat(MSG_ENTITY, flChanged);
SENDENTITY_COORD(origin[0], ENVINSTRUCTOR_CHANGED_ORIGIN)
SENDENTITY_COORD(origin[1], ENVINSTRUCTOR_CHANGED_ORIGIN)
SENDENTITY_COORD(origin[2], ENVINSTRUCTOR_CHANGED_ORIGIN)
SENDENTITY_STRING(m_strIcon, ENVINSTRUCTOR_CHANGED_IMAGE)
SENDENTITY_STRING(m_strIconOff, ENVINSTRUCTOR_CHANGED_IMAGE_OFF)
SENDENTITY_STRING(m_strText, ENVINSTRUCTOR_CHANGED_TEXT)
SENDENTITY_COORD(m_vecTextColor[0], ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
SENDENTITY_COORD(m_vecTextColor[1], ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
SENDENTITY_COORD(m_vecTextColor[2], ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
SENDENTITY_FLOAT(m_flTimeOut, ENVINSTRUCTOR_CHANGED_TIMEOUT)
SENDENTITY_FLOAT(m_flOffset, ENVINSTRUCTOR_CHANGED_OFFSET)
SENDENTITY_BYTE(m_bEnabled, ENVINSTRUCTOR_CHANGED_STATE)
return true;
}
#endif
#ifdef CLIENT
void
env_instructor_hint::ReceiveEntity(float flNew, float flChanged)
{
READENTITY_COORD(origin[0], ENVINSTRUCTOR_CHANGED_ORIGIN)
READENTITY_COORD(origin[1], ENVINSTRUCTOR_CHANGED_ORIGIN)
READENTITY_COORD(origin[2], ENVINSTRUCTOR_CHANGED_ORIGIN)
READENTITY_STRING(m_strIcon, ENVINSTRUCTOR_CHANGED_IMAGE)
READENTITY_STRING(m_strIconOff, ENVINSTRUCTOR_CHANGED_IMAGE_OFF)
READENTITY_STRING(m_strText, ENVINSTRUCTOR_CHANGED_TEXT)
READENTITY_COORD(m_vecTextColor[0], ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
READENTITY_COORD(m_vecTextColor[1], ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
READENTITY_COORD(m_vecTextColor[2], ENVINSTRUCTOR_CHANGED_TEXT_COLOR)
READENTITY_FLOAT(m_flTimeOut, ENVINSTRUCTOR_CHANGED_TIMEOUT)
READENTITY_FLOAT(m_flOffset, ENVINSTRUCTOR_CHANGED_OFFSET)
READENTITY_BYTE(m_bEnabled, ENVINSTRUCTOR_CHANGED_STATE)
setorigin(this, origin);
if (m_bEnabled != m_bOldHintState) {
m_flHintTime = m_flTimeOut;
}
m_bOldHintState = m_bEnabled;
}
void
env_instructor_hint::postdraw(void)
{
bool visible = false;
bool inView = false;
vector positionValues;
if (!m_bEnabled)
return;
if (m_flHintTime <= 0.0f)
return;
/* calculation for the edge positions */
{
vector delta;
vector p2 = g_view.GetCameraOrigin();
vector ang = g_view.GetCameraAngle();
vector outputValue;
float leftValue;
float upValue;
makevectors(ang);
delta = normalize (origin - p2);
leftValue = delta * v_right;
upValue = delta * -v_up;
positionValues[0] = (delta * v_forward);
positionValues[1] = (leftValue + 1.0f) * 0.5f;
positionValues[2] = (upValue + 1.0f) * 0.5f;
if (fabs(leftValue) > fabs(upValue)) {
/* clamp leftvalue */
if (positionValues[1] > 0.5)
positionValues[1] = 1.0f;
else
positionValues[1] = 0.0f;
} else {
/* clamp upvalue */
if (positionValues[2] > 0.5)
positionValues[2] = 1.0f;
else
positionValues[2] = 0.0f;
}
/* within field of view... */
if (positionValues[0] > (g_view.GetAFOV()/180)) {
traceline(p2, origin, MOVE_WORLDONLY, self);
/* totally visible */
if (trace_fraction == 1.0) {
visible = true;
}
inView = true;
}
}
vector iconPos;
vector textPos;
vector hintPos;
float textLength = Font_StringWidth(m_strText, true, FONT_CON);
float sideOffset = textLength + 64.0f;
float a = (visible == false) ? 0.25 : 1.0f;
a = 1.0f;
/* in-world position of the center */
hintPos = project(origin + [0, m_flOffset]) - [(textLength * 0.5f), 0];
if (inView == false) {
hintPos[0] = Math_Lerp(32.0f, video_res[0] - sideOffset, positionValues[1]);
hintPos[1] = Math_Lerp(32.0f, video_res[1] - 32.0f, positionValues[2]);
}
/* draw the thing */
iconPos = hintPos - [32, 32];
textPos = hintPos + [48.0f, 0];
drawpic(iconPos, m_strIcon, [64, 64], [1,1,1], a);
Font_DrawText_RGBA(textPos + [1,1], m_strText, [0,0,0], a, FONT_CON);
Font_DrawText_RGBA(textPos, m_strText, m_vecTextColor, a, FONT_CON);
m_flHintTime -= clframetime;
}
#endif

View File

@ -35,8 +35,9 @@ by players.
- "Text" : A localised string to display next to it.
# INPUTS
- "Enable" : Enables the entity.
- "Disable" : Disables the entity.
- "Enable" : Enable the entity.
- "Disable" : Disable the entity.
- "Toggle" : Toggles between enabled/disabled states.
# TRIVIA
This entity was introduced in Obsidian Conflict (2006).
@ -74,7 +75,6 @@ info_waypoint::info_waypoint(void)
{
m_strIcon =
m_strText = __NULL__;
m_bEnabled = false;
}
#ifdef SERVER
@ -99,7 +99,6 @@ info_waypoint::Save(float handle)
super::Save(handle);
SaveString(handle, "m_strIcon", m_strIcon);
SaveString(handle, "m_strText", m_strText);
SaveBool(handle, "m_bEnabled", m_bEnabled);
}
void
@ -112,9 +111,6 @@ info_waypoint::Restore(string strKey, string strValue)
case "m_strText":
m_strText = ReadString(strValue);
break;
case "m_bEnabled":
m_bEnabled = ReadBool(strValue);
break;
default:
super::Restore(strKey, strValue);
}

View File

@ -0,0 +1,156 @@
/*
* Copyright (c) 2023 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.
*/
#ifdef SERVER
/*!QUAKED logic_achievement (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
# OVERVIEW
Unlocks achievements or aids in the progression of them.
# KEYS
- "targetname" : Name
- "AchievementEvent" : Identifier of the achievement.
- "StartDisabled" : Entity will have to be enabled in order to work when set to 1.
# INPUTS
- "FireEvent" : Triggers the achievement.
- "Enable" : Enable the entity.
- "Disable" : Disable the entity.
- "Toggle" : Toggles between enabled/disabled states.
# OUTPUTS
- "OnFired" : Triggered when the 'FireEvent' is received.
# NOTES
Ensure to prefix the value of the `AchievementEvent` key with `ACHIEVEMENT_EVENT_`. For example, if you are using SteamWorks and have your achievement on there named `FOOBAR` then you want the value to be `ACHIEVEMENT_EVENT_FOOBAR`.
# TRIVIA
This entity was introduced in The Orange Box (2007) for Xbox 360.
*/
class
logic_achievement:NSPointTrigger
{
public:
void logic_achievement(void);
/** overrides */
virtual void Save(float);
virtual void Restore(string, string);
virtual void SpawnKey(string, string);
virtual void Spawned(void);
virtual void Respawn(void);
virtual void Input(entity, string, string);
virtual void Trigger(entity, triggermode_t);
nonvirtual void CallEvent(entity);
private:
string m_strAchievementEvent;
string m_strOnFired;
};
void
logic_achievement::logic_achievement(void)
{
m_strAchievementEvent = __NULL__;
m_strOnFired = __NULL__;
}
void
logic_achievement::Save(float handle)
{
SaveString(handle, "m_strAchievementEvent", m_strAchievementEvent);
SaveString(handle, "m_strOnFired", m_strOnFired);
}
void
logic_achievement::Restore(string keyName, string setValue)
{
switch (keyName) {
case "m_strAchievementEvent":
m_strAchievementEvent = ReadString(setValue);
break;
case "m_strOnFired":
m_strOnFired = ReadString(setValue);
break;
default:
super::Restore(keyName, setValue);
}
}
void
logic_achievement::SpawnKey(string keyName, string setValue)
{
switch (keyName) {
case "AchievementEvent":
m_strAchievementEvent = ReadString(setValue);
break;
case "OnFired":
m_strOnFired = PrepareOutput(m_strOnFired, setValue);
break;
default:
super::SpawnKey(keyName, setValue);
}
}
void
logic_achievement::Spawned(void)
{
super::Spawned();
if (m_strOnFired)
m_strOnFired = CreateOutput(m_strOnFired);
}
void
logic_achievement::Respawn(void)
{
InitPointTrigger();
}
void
logic_achievement::Input(entity activatorEntity, string inputName, string dataField)
{
switch (inputName) {
case "FireEvent":
CallEvent(activatorEntity);
break;
default:
super::Input(activatorEntity, inputName, dataField);
}
}
void
logic_achievement::Trigger(entity activatorEntity, triggermode_t state)
{
CallEvent(activatorEntity);
}
void
logic_achievement::CallEvent(entity targetPlayer)
{
if (m_bEnabled == false) {
return;
}
UseOutput(targetPlayer, m_strOnFired);
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_ACHIEVEMENT);
WriteString(MSG_MULTICAST, m_strAchievementEvent);
msg_entity = targetPlayer;
multicast([0,0,0], MULTICAST_ONE_R);
}
#endif

View File

@ -14,6 +14,7 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef SERVER
enumflags
{
SPEAKFL_SILENT
@ -33,6 +34,7 @@ string g_speaker_hlpresets[] = {
"!C3A1_",
"!C3A2_"
};
#endif
/*!QUAKED speaker (1 0 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
@ -69,7 +71,8 @@ speaker:NSTalkMonster
{
public:
void speaker(void);
#ifdef SERVER
/* overrides */
virtual void Save(float);
virtual void Restore(string,string);
@ -79,18 +82,32 @@ public:
nonvirtual void Announce(void);
virtual void EvaluateEntity(void);
virtual float SendEntity(entity,float);
#endif
#ifdef CLIENT
virtual void ReceiveEntity(float, float);
#endif
#ifdef SERVER
private:
string m_strSentence;
float m_flVolume;
#endif
};
void
speaker::speaker(void)
{
#ifdef SERVER
m_strSentence = __NULL__;
m_flVolume = 1.0f;
#endif
}
#ifdef SERVER
void
speaker::Save(float handle)
{
@ -139,10 +156,7 @@ speaker::SpawnKey(string strKey, string strValue)
void
speaker::Respawn(void)
{
/* force this thing to be networked */
SetModel("models/player.mdl");
SetOrigin(GetSpawnOrigin());
Hide();
if (HasSpawnFlags(SPEAKFL_SILENT) == false)
ScheduleThink(Announce, 10.0f);
@ -173,3 +187,42 @@ speaker::Trigger(entity eAct, triggermode_t foo)
{
ScheduleThink(Announce, 0.0f);
}
void
speaker::EvaluateEntity(void)
{
EVALUATE_VECTOR(origin, 0, MONFL_CHANGED_ORIGIN_X)
EVALUATE_VECTOR(origin, 1, MONFL_CHANGED_ORIGIN_Y)
EVALUATE_VECTOR(origin, 2, MONFL_CHANGED_ORIGIN_Z)
}
/* Make sure StartFrame calls this */
float
speaker::SendEntity(entity ePEnt, float flChanged)
{
if (clienttype(ePEnt) != CLIENTTYPE_REAL)
return (0);
WriteByte(MSG_ENTITY, ENT_SPEAKER);
/* broadcast how much data is expected to be read */
WriteFloat(MSG_ENTITY, flChanged);
SENDENTITY_COORD(origin[0], MONFL_CHANGED_ORIGIN_X)
SENDENTITY_COORD(origin[1], MONFL_CHANGED_ORIGIN_Y)
SENDENTITY_COORD(origin[2], MONFL_CHANGED_ORIGIN_Z)
return (1);
}
#endif
#ifdef CLIENT
void
speaker::ReceiveEntity(float flNew, float flChanged)
{
READENTITY_COORD(origin[0], MONFL_CHANGED_ORIGIN_X)
READENTITY_COORD(origin[1], MONFL_CHANGED_ORIGIN_Y)
READENTITY_COORD(origin[2], MONFL_CHANGED_ORIGIN_Z)
SetOrigin(origin);
}
#endif

View File

@ -394,11 +394,9 @@ initents(void)
PMove_Init();
/** compat... */
precache_sound("misc/null.wav");
precache_sound("common/null.wav");
Sound_Precache("player.GaspLight");
Sound_Precache("player.GaspHeavy");
Sound_Precache("Player.GaspLight");
Sound_Precache("Player.GaspHeavy");
Sound_Precache("player.WaterEnter");
Sound_Precache("player.WaterExit");
Sound_Precache("Player.Death");
@ -407,9 +405,12 @@ initents(void)
Sound_Precache("Player.Swim");
Sound_Precache("Player.DenyWeaonSelection");
Sound_Precache("Player.WeaponSelected");
Sound_Precache("Player.FallDamage");
Sound_Precache("Player.LightFall");
Sound_Precache("Player.FallGib");
Sound_Precache("damage_bullet.hit");
Sound_Precache("player.spraylogo");
Sound_Precache("SprayCan.Paint");
Sound_Precache("step_ladder.left");
Sound_Precache("step_ladder.right");
@ -558,6 +559,9 @@ ConsoleCmd(string cmd)
Way_Cmd();
break;
#endif
case "listSoundDef":
Sound_DebugList();
break;
default:
return (0);
}

View File

@ -35,4 +35,8 @@ NSBrushTrigger::InitBrushTrigger(void)
SetModel(GetSpawnModel());
SetMovetype(MOVETYPE_NONE);
SetSolid(SOLID_BSPTRIGGER);
#ifdef SERVER
m_bEnabled = (m_bStartDisabled) ? false : true;
#endif
}

View File

@ -303,20 +303,13 @@ NSClientPlayer::predraw(void)
if (entnum == player_localentnum)
g_view.SetDrawLocalPlayer(true);
/* sucks we can't draw a shadow on this thing, maybe in the future when FTEQW allows it */
if (p_model) {
if (p_model.GetRenderMode() != RM_DONTRENDER)
addentity(p_model);
}
} else { /* we're doing first person stuff */
/* flags that the model appear in mirrors only */
renderflags |= RF_EXTERNALMODEL;
/* ditto */
p_model.renderflags |= RF_EXTERNALMODEL;
/* give mods a chance to de-render attachments */
UpdatePlayerAttachments(false);
UpdatePlayerAttachments(true);
Weapons_PreDraw((player)this, false);
/* this is here just to make sure our view hides us if it's the local player */
@ -324,6 +317,16 @@ NSClientPlayer::predraw(void)
g_view.SetDrawLocalPlayer(false);
}
if (p_model) {
p_model.entnum = entnum;
p_model.drawmask = 0;
if (p_model.GetRenderMode() != RM_DONTRENDER)
addentity(p_model);
p_model.entnum = 0;
}
/* this needs to be called absolutely last */
/* we're calling this so that the shadow can still be drawn */
if (GetRenderMode() != RM_DONTRENDER)
@ -1162,10 +1165,10 @@ NSClientPlayer::InputUse_Down(void)
/* Some entities want to support Use spamming */
if (HasFlags(FL_USE_RELEASED) == false) {
sound(this, CHAN_ITEM, "common/wpn_select.wav", 0.25, ATTN_IDLE);
StartSoundDef("Player.WeaponSelected", CHAN_ITEM, false);
}
} else {
sound(this, CHAN_ITEM, "common/wpn_denyselect.wav", 0.25, ATTN_IDLE);
StartSoundDef("Player.DenyWeaponSelection", CHAN_ITEM, false);
flags &= ~FL_USE_RELEASED;
}
}
@ -1208,27 +1211,15 @@ NSClientPlayer::Footsteps_Update(void)
return;
if (waterlevel == 1) {
if (step)
StartSoundDef("step_slosh.left", CHAN_BODY, true);
else
StartSoundDef("step_slosh.right", CHAN_BODY, true);
step_time = time + 0.35f;
StartSoundDef("Player.Wade", CHAN_BODY, true);
step_time = time + 2.0f;
return;
} else if (waterlevel == 2) {
if (step)
StartSoundDef("step_wade.left", CHAN_BODY, true);
else
StartSoundDef("step_wade.right", CHAN_BODY, true);
step_time = time + 1.0f;
StartSoundDef("Player.Wade", CHAN_BODY, true);
step_time = time + 2.0f;
return;
} else if (waterlevel == 3) {
if (step)
StartSoundDef("step_swim.left", CHAN_BODY, true);
else
StartSoundDef("step_swim.right", CHAN_BODY, true);
StartSoundDef("Player.Swim", CHAN_BODY, true);
step_time = time + 2.0f;
return;
} else {

View File

@ -39,6 +39,19 @@ NSItem::Spawned(void)
void
NSItem::Respawn(void)
{
/* we need to delay the DropToFloor() by at least a frame.
otherwise they may just fall through an entity (func_wall, func_train etc.)
that came after this entity in the lump. */
static void AdjustSpawnPos(void) {
RestoreAngles();
SetOrigin(GetSpawnOrigin());
if (!m_bFloating) {
DropToFloor();
SetMovetype(MOVETYPE_TOSS);
}
}
SetSolid(SOLID_TRIGGER);
SetOrigin(GetSpawnOrigin());
botinfo = BOTINFO_WEAPON;
@ -54,12 +67,7 @@ NSItem::Respawn(void)
}
SetSize([-16,-16,0], [16,16,16]);
ReleaseThink();
if (!m_bFloating) {
DropToFloor();
SetMovetype(MOVETYPE_TOSS);
}
ScheduleThink(AdjustSpawnPos, 0.0f);
}
void

View File

@ -148,7 +148,7 @@ typedef enumflags
MSF_RESERVED2,
MSF_IGNOREPLAYER,
MSF_WAITFORSCRIPT,
MSF_PREDISASTER,
MSF_RESERVED3,
MSF_FADECORPSE,
MSF_MULTIPLAYER,
MSF_FALLING,
@ -381,6 +381,8 @@ public:
/** Returns TRUE if 'enemy' should be considered a valid target for killing */
nonvirtual bool IsValidEnemy(entity);
/** Returns TRUE if the monster is currently on route to a position. */
virtual bool IsOnRoute(void);
/* sequences */
/** Internal use only. Called when a sequence is done. */

View File

@ -646,6 +646,12 @@ NSMonster::IsValidEnemy(entity enny)
return true;
}
bool
NSMonster::IsOnRoute(void)
{
return (m_iNodes || m_pathTarget) && (GetState() == MONSTER_IDLE || GetState() == MONSTER_ALERT) ? true : false;
}
static bool
NSMonster_TraceAgainsTarget(NSMonster monster, NSEntity target)
{
@ -1258,12 +1264,11 @@ NSMonster::RouteEnded(void)
void
NSMonster::WalkRoute(void)
{
/* we're busy shooting at something, don't walk */
if (GetState() == MONSTER_AIMING && m_eEnemy) {
input_angles = vectoangles(m_eEnemy.origin - origin);
input_angles[0] = input_angles[2] = 0;
} else if ((m_iNodes || m_pathTarget) && (GetState() == MONSTER_IDLE || GetState() == MONSTER_ALERT)) {
} else if (IsOnRoute()) {
input_angles = GetRouteDirection();
input_angles[0] = input_angles[2] = 0;
input_movevalues = GetRouteMovevalues() * m_flSequenceSpeed;
@ -1548,8 +1553,30 @@ NSMonster::Touch(entity eToucher)
if (autocvar(pm_pushMonsters, 0))
if (eToucher.movetype == MOVETYPE_WALK) {
if (eToucher.absmin[2] < origin[2])
velocity = normalize(eToucher.origin - origin) * -128;
if (eToucher.absmin[2] < origin[2]) {
float bestYaw = 0.0f;
float best_fraction = 0.0f;
vector bestPos = g_vec_null;
for (float yaw = angles[1]; yaw < (angles[1] + 360.0f); yaw += 1.0f) {
makevectors([0, yaw, 0]);
tracebox(origin, mins, maxs, origin + (v_forward * 128.0f), FALSE, this);
if (trace_startsolid) {
bestYaw = random(0, 360);
break;
}
if (trace_fraction > best_fraction) {
best_fraction = trace_fraction;
bestYaw = yaw;
bestPos = trace_endpos;
}
}
RouteToPosition(bestPos);
m_flSequenceSpeed = GetWalkSpeed();
}
}
}

View File

@ -19,6 +19,10 @@ NSPointTrigger::InitPointTrigger(void)
{
SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
SetSolid(SOLID_TRIGGER);
#ifdef SERVER
m_bEnabled = (m_bStartDisabled) ? false : true;
#endif
}

View File

@ -170,6 +170,6 @@ CSEv_Spraylogo(void)
spray.SendEntity = Spray_SendEntity;
spray.SendFlags = 1;
Sound_Play(self, CHAN_VOICE, "player.spraylogo");
Sound_Play(self, CHAN_VOICE, "SprayCan.Paint");
}
#endif

View File

@ -308,6 +308,9 @@ NSTalkMonster::Speak(string sentence)
void
NSTalkMonster::TalkPlayerGreet(void)
{
if (HasSpawnFlags(MSF_GAG))
return;
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
@ -336,10 +339,12 @@ NSTalkMonster::TalkPlayerGreet(void)
void
NSTalkMonster::TalkPlayerIdle(void)
{
if (HasSpawnFlags(MSF_GAG))
return;
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
if (HasSpawnFlags(MSF_PREDISASTER))
return;
if (m_flNextSentence > time)
return;
@ -366,10 +371,12 @@ NSTalkMonster::TalkPlayerIdle(void)
void
NSTalkMonster::TalkPlayerAsk(void)
{
if (HasSpawnFlags(MSF_GAG))
return;
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
if (HasSpawnFlags(MSF_PREDISASTER))
return;
if (m_flNextSentence > time)
return;
@ -391,6 +398,9 @@ NSTalkMonster::TalkPlayerAsk(void)
void
NSTalkMonster::TalkPlayerWounded1(void)
{
if (HasSpawnFlags(MSF_GAG))
return;
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
@ -417,6 +427,9 @@ NSTalkMonster::TalkPlayerWounded1(void)
void
NSTalkMonster::TalkPlayerWounded2(void)
{
if (HasSpawnFlags(MSF_GAG))
return;
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
@ -444,6 +457,9 @@ NSTalkMonster::TalkPlayerWounded2(void)
void
NSTalkMonster::TalkPlayerWounded3(void)
{
if (HasSpawnFlags(MSF_GAG))
return;
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
@ -468,6 +484,9 @@ NSTalkMonster::TalkPlayerWounded3(void)
void
NSTalkMonster::TalkPanic(void)
{
if (HasSpawnFlags(MSF_GAG))
return;
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
@ -519,6 +538,9 @@ NSTalkMonster::TalkDenyFollow(void)
void
NSTalkMonster::Touch(entity eToucher)
{
if (eToucher == world)
return;
if (eToucher == m_eFollowing) {
makevectors(eToucher.angles);
velocity = v_forward * 250.0f;
@ -634,23 +656,35 @@ NSTalkMonster::FollowPlayer(void)
void
NSTalkMonster::PanicFrame(void)
{
float bestYaw = 0.0f;
float best_fraction = 0.0f;
float secondBest = 0.0f;
m_iFlags |= MONSTER_METPLAYER;
input_movevalues = [240, 0, 0];
if (m_flTraceTime < time) {
traceline(origin, origin + (v_forward * 64), FALSE, this);
if (trace_fraction < 1.0f) {
m_flChangePath = 0.0f;
for (float yaw = -180.0f; yaw < 180.0f; yaw += 1.0f) {
makevectors([0, yaw, 0]);
tracebox(origin, mins, maxs, origin + (v_forward * 1024), FALSE, this);
if (trace_startsolid) {
bestYaw = random(0, 360);
break;
}
if (trace_fraction > best_fraction) {
best_fraction = trace_fraction;
bestYaw = yaw;
}
}
m_flTraceTime = time + 0.5f;
angles[1] = Math_FixDelta(bestYaw + random(-25, 25));
input_angles[1] = angles[1];
v_angle[1] = angles[1];
m_flTraceTime = time + 0.5f + random();
}
if (m_flChangePath < time) {
input_angles[1] -= 180 + ((random() - 0.5) * 90);
input_angles[1] = Math_FixDelta(input_angles[1]);
m_flChangePath = time + floor(random(2,10));
}
if (m_flNextSentence > time)
return;
@ -1112,7 +1146,7 @@ NSTalkMonster_ParseSentence(void)
ent = findfloat(world, entnum, e);
if (ent) {
if (ent.classname != "NSTalkMonster" && ent.classname != "ambient_generic")
if (ent.classname != "speaker" && ent.classname != "NSTalkMonster" && ent.classname != "ambient_generic")
NSMonster_Log("^3 NSTalkMonster_ParseSentence ^7: Entity %d not a NSTalkMonster!", e);
else {
targ = (NSTalkMonster)ent;

View File

@ -55,6 +55,8 @@ enumflags
TOUCHFILTER_FRIENDLIES,
TOUCHFILTER_CLIENTSINVEHICLES,
TOUCHFILTER_EVERYTHING,
TOUCHFILTER_PADDING1,
TOUCHFILTER_PADDING2,
TOUCHFILTER_CLIENTSNOTINVEHICLES,
TOUCHFILTER_DEBRIS,
TOUCHFILTER_NPCSINVEHICLES,
@ -154,6 +156,10 @@ private:
int m_iUseType;
int m_iValue;
bool m_bEnabled;
bool m_bStartDisabled;
bool m_bIsModern;
float team_no;
/* legacy trigger architecture */

View File

@ -30,6 +30,9 @@ NSTrigger::NSTrigger(void)
team = 0;
m_iValue = 0i;
m_flDelay = 0.0f;
m_bStartDisabled = false;
m_bEnabled = true;
m_bIsModern = false;
#endif
}
@ -236,6 +239,9 @@ NSTrigger::Save(float handle)
SaveInt(handle, "m_iValue", m_iValue);
SaveFloat(handle, "m_flDelay", m_flDelay);
SaveString(handle, "m_strGlobalName", m_strGlobalName);
SaveBool(handle, "m_bStartDisabled", m_bStartDisabled);
SaveBool(handle, "m_bEnabled", m_bEnabled);
SaveBool(handle, "m_bIsModern", m_bIsModern);
}
void
NSTrigger::Restore(string strKey, string strValue)
@ -271,6 +277,15 @@ NSTrigger::Restore(string strKey, string strValue)
case "m_strGlobalName":
m_strGlobalName = ReadString(strValue);
break;
case "m_bStartDisabled":
m_bStartDisabled = ReadBool(strValue);
break;
case "m_bEnabled":
m_bEnabled = ReadBool(strValue);
break;
case "m_bIsModern":
m_bIsModern = ReadBool(strValue);
break;
default:
super::Restore(strKey, strValue);
}
@ -283,6 +298,15 @@ NSTrigger::Input(entity eAct, string strInput, string strData)
case "Trigger":
Trigger(eAct, TRIG_TOGGLE);
break;
case "Enable":
m_bEnabled = true;
break;
case "Disable":
m_bEnabled = false;
break;
case "Toggle":
m_bEnabled = (m_bEnabled) ? false : true;
break;
default:
super:: Input(eAct, strInput, strData);
}
@ -333,6 +357,10 @@ NSTrigger::SpawnKey(string strKey, string strValue)
case "globalname":
m_strGlobalName = ReadString(strValue);
break;
case "StartDisabled":
m_bStartDisabled = ReadBool(strValue);
m_bIsModern = true;
break;
#endif
default:
super::SpawnKey(strKey, strValue);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2023 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
@ -25,6 +25,7 @@ typedef enum
ENT_PHYSICS, /**< of type NSPhysicsEntity */
ENT_MONSTER, /**< of type NSMonster */
ENT_TALKMONSTER, /**< of type NSTalkMonster */
ENT_SPEAKER, /**< of type speaker */
ENT_PLAYER, /**< of type NSClientPlayer */
ENT_WEAPON, /**< of type NSWeapon */
ENT_SPECTATOR, /**< of type NSClientSpectator */
@ -37,8 +38,9 @@ typedef enum
ENT_PROJECTEDTEXTURE, /**< of type env_projectedtexture */
ENT_SPOTLIGHT, /**< of type point_spotlight */
ENT_FOG, /*<< of type env_fog */
ENT_STEAM,
ENT_STEAM, /*<< of type env_steam */
ENT_FOGCONTROLLER, /**< of type env_fog_controller */
ENT_CASCADELIGHT, /*<< of type env_cascade_light */
ENT_LASER, /**< of type env_laser */
ENT_PARTSYSTEM, /**< of type info_particle_system */
ENT_SPRITE, /**< of type env_sprite */
@ -56,6 +58,7 @@ typedef enum
ENT_BUBBLES, /**< of type env_bubbles */
ENT_CONVEYOR, /**< of type func_conveyor */
ENT_WAYPOINT, /**< of type info_waypoint */
ENT_INSTRUCTOR, /**< of type env_instructor_hint */
ENT_PUSH, /**< of type trigger_push */
ENT_SEPARATOR, /**< This is a separator. This separator is used by you to add game-specific networked entities. When declaring your own entity-update types, you want the first value to equal ENT_SEPARATOR at all times to ensure you'll not be overriding existing slots. */
} entupdate_t;

View File

@ -59,5 +59,6 @@ enum
EV_BEAMCYLINDER,
EV_MUZZLEFLASH,
EV_TRACEDEBUG,
EV_ACHIEVEMENT,
EV_SEPARATOR
};

View File

@ -81,9 +81,9 @@ NSClientPlayer::Physics_Fall(float flDownforce)
}
Damage_Apply(this, world, fFallDamage, 0, DMG_FALL | DMG_SKIP_ARMOR);
Sound_Play(this, CHAN_VOICE, "player.fall");
StartSoundDef("Player.FallDamage", CHAN_VOICE, true);
} else if (flDownforce >= PHY_FALL_DISTANCE) {
Sound_Play(this, CHAN_VOICE, "player.lightfall");
StartSoundDef("Player.LightFall", CHAN_VOICE, true);
}
#endif
}
@ -135,6 +135,9 @@ NSClientPlayer::Physics_Crouch(void)
void
NSClientPlayer::Physics_Jump(void)
{
if (GetMovetype() != MOVETYPE_WALK)
return;
/* we're underwater... */
if (WaterLevel() >= 2) {
/* different water contents allow for different speeds */
@ -241,7 +244,6 @@ NSClientPlayer::Physics_WaterMove(void)
return;
}
#ifdef SERVER
if (WaterLevel() > 0) {
if (watertype == CONTENT_LAVA) {
if (m_flPainTime < time) {
@ -255,14 +257,13 @@ NSClientPlayer::Physics_WaterMove(void)
}
}
}
#endif
/* we've just exited water */
if (WaterLevel() != 3) {
if (m_flUnderwaterTime < time) {
Sound_Play(this, CHAN_BODY, "player.gaspheavy");
StartSoundDef("Player.GaspHeavy", CHAN_BODY, true);
} else if (m_flUnderwaterTime < time + 9) {
Sound_Play(this, CHAN_BODY, "player.gasplight");
StartSoundDef("Player.GaspLight", CHAN_BODY, true);
}
m_flUnderwaterTime = time + 12;
} else if (m_flUnderwaterTime < time) {
@ -279,7 +280,7 @@ NSClientPlayer::Physics_WaterMove(void)
if (!WaterLevel()){
if (GetFlags() & FL_INWATER) {
#ifdef SERVER
Sound_Play(this, CHAN_BODY, "player.waterexit");
StartSoundDef("Player.WaterExit", CHAN_BODY, true);
#endif
RemoveFlags(FL_INWATER);
}
@ -288,7 +289,7 @@ NSClientPlayer::Physics_WaterMove(void)
if (!(GetFlags() & FL_INWATER)) {
#ifdef SERVER
Sound_Play(this, CHAN_BODY, "player.waterenter");
StartSoundDef("Player.WaterEnter", CHAN_BODY, true);
m_flPainTime = 0;
#endif
AddFlags(FL_INWATER);
@ -303,53 +304,54 @@ NSClientPlayer::Physics_WaterMove(void)
float
NSClientPlayer::Physics_MaxSpeed(void)
{
float maxspeed = serverkeyfloat("phy_maxspeed");
float desiredspeed = (GetFlags() & FL_CROUCHING) ? PMOVE_STEP_WALKSPEED : maxspeed;
return min(desiredspeed, maxspeed);
float maxValue = serverkeyfloat("phy_maxspeed");
float wishSpeed = (GetFlags() & FL_CROUCHING) ? PMOVE_STEP_WALKSPEED : maxValue;
return min(wishSpeed, maxValue);
}
void
NSClientPlayer::Physics_InputPreMove(void)
{
NSVehicle veh = (NSVehicle)vehicle;
bool canmove = true;
NSVehicle currentVehicle = (NSVehicle)vehicle;
bool canMove = true;
/* when pressing the 'use' button, we also walk slower for precision */
if (input_buttons & INPUT_BUTTON5) {
input_movevalues *= 0.25;
}
bool flying = ((GetMovetype() == MOVETYPE_NOCLIP) || (GetMovetype() == MOVETYPE_FLY));
if (flying == true) {
/* move camera up (noclip, fly) when holding jump */
if (input_buttons & INPUT_BUTTON2) {
input_movevalues[2] = 240;
}
/* move camera down (noclip, fly) when holding crouching */
if (input_buttons & INPUT_BUTTON8) {
input_movevalues[2] = -240;
}
/* find all the valid ways to freeze a player... */
if (currentVehicle) {
if (currentVehicle.PreventPlayerMovement() == true)
canMove = false;
}
/* find all the valid ways to freeze a player... */
if (veh)
if (veh.PreventPlayerMovement() == true)
canmove = false;
if (flags & FL_FROZEN || movetype == MOVETYPE_NONE)
canmove = false;
if (flags & FL_FROZEN || movetype == MOVETYPE_NONE) {
canMove = false;
}
/* freeze in place */
if (canmove == false) {
if (canMove == false) {
input_movevalues = [0,0,0];
input_buttons &= ~INPUT_BUTTON2;
}
/* clamp movement values to max speed */
{
float wishSpeed = vlen(input_movevalues);
if (wishSpeed > maxspeed) {
wishSpeed = maxspeed;
}
input_movevalues = normalize(input_movevalues) * wishSpeed;
}
/* suppress crouching in vehicles */
if (veh)
if (veh.CanDriverCrouch() == false)
if (currentVehicle) {
if (currentVehicle.CanDriverCrouch() == false)
input_buttons &= ~INPUT_BUTTON8;
}
}
/* timers get processed here after physics are run */
@ -379,7 +381,7 @@ NSClientPlayer::Physics_Run(void)
{
float flFallVel = (flags & FL_ONGROUND) ? 0 : -velocity[2];
float flBaseVel = basevelocity[2];
bool onGround = (flags & FL_ONGROUND) ? true : false;
bool wasOnGround = (flags & FL_ONGROUND) ? true : false;
saved_input_movevalues = input_movevalues;
saved_input_buttons = input_buttons;
@ -417,7 +419,7 @@ NSClientPlayer::Physics_Run(void)
Physics_CheckJump(FALSE);
if (onGround == false && (flags & FL_ONGROUND)) {
if (wasOnGround == false && (flags & FL_ONGROUND)) {
if (waterlevel != 0) {
flFallVel = 0;
}

View File

@ -47,6 +47,7 @@ PMoveCustom_StartFrame(void)
PMoveCustom_UpdateVar("phy_maxspeed", "pm_maxspeed");
PMoveCustom_UpdateVar("phy_noclipspeed", "pm_noclipspeed");
PMoveCustom_UpdateVar("phy_noclipaccelerate", "pm_noclipaccelerate");
PMoveCustom_UpdateVar("phy_nospeedcap", "pm_nospeedcap");
}
#endif
@ -82,6 +83,9 @@ PMoveCustom_Categorize(void)
bool inladder = false;
vector testPos;
if (self.movetype == MOVETYPE_NOCLIP)
return;
tracebox(self.origin, self.mins, self.maxs, self.origin - [0,0,1], MOVE_NORMAL, self);
if (!trace_startsolid) {
@ -97,6 +101,7 @@ PMoveCustom_Categorize(void)
}
} else {
self.groundentity = __NULL__;
self.flags |= FL_ONGROUND;
}
self.flags &= ~FL_WATERJUMP;
@ -198,7 +203,7 @@ PMoveCustom_AccelWater(float move_time, float premove)
wish_speed = vlen(vecWishVel);
if (wish_speed > self.maxspeed) {
if (serverkeyfloat("phy_nospeedcap") == 0 && wish_speed > self.maxspeed) {
wish_speed = self.maxspeed;
}
@ -258,11 +263,17 @@ PMoveCustom_AccelFriction(float move_time, float premove, vector wish_dir, float
float flFriction;
vector vecTemp;
#ifdef SERVER
/* too finicky with monsters between the various game settings */
if (self.flags & FL_MONSTER) {
self.velocity = wish_dir * wish_speed;
return;
NSMonster checkMe = (NSMonster)self;
if (checkMe.IsOnRoute() == true && checkMe.HasFlags(FL_ONGROUND) == true) {
self.velocity = wish_dir * wish_speed;
return;
}
}
#endif
flApplyFriction = serverkeyfloat("phy_friction");
@ -305,7 +316,12 @@ PMoveCustom_AccelFriction(float move_time, float premove, vector wish_dir, float
if (flFriction < 0) {
self.velocity = [0,0,0];
} else {
self.velocity = self.velocity * flFriction;
self.velocity[0] = self.velocity[0] * flFriction;
self.velocity[1] = self.velocity[1] * flFriction;
/* don't apply friction to horizontal movement... or else jumps get clamped */
if (self.flags & FL_JUMPRELEASED)
self.velocity[2] = self.velocity[2] * flFriction;
}
}
@ -332,33 +348,14 @@ PMoveCustom_AccelNoclip(float move_time, float premove, vector wish_dir, float w
}
/* apply friction */
if (self.velocity[0] || self.velocity[1]) {
if (vlen(self.velocity)) {
vecTemp = self.velocity;
vecTemp[2] = 0;
flFriction = vlen(vecTemp);
/* Next few lines of code assumes self is using player's hull, however it could be a monster
who use differen hull size, therefore it is invalid, so we probably better of using mins/maxs,
on the other hand edge friction is probably not that important. */
// if the leading edge is over a dropoff, increase friction
vecTemp = self.origin + normalize(vecTemp) * 16 + [0,0,1] * self.mins[2];
traceline(vecTemp, vecTemp + [0,0,-34], TRUE, self);
// apply friction
if (trace_fraction == 1.0) {
if (flFriction < serverkeyfloat("phy_stopspeed")) {
flFriction = 1 - move_time * (serverkeyfloat("phy_stopspeed") / flFriction) * flApplyFriction * serverkeyfloat("phy_edgefriction");
} else {
flFriction = 1 - move_time * flApplyFriction * serverkeyfloat("phy_edgefriction");
}
if (flFriction < serverkeyfloat("phy_stopspeed")) {
flFriction = 1 - move_time * (serverkeyfloat("phy_stopspeed") / flFriction) * flApplyFriction;
} else {
if (flFriction < serverkeyfloat("phy_stopspeed")) {
flFriction = 1 - move_time * (serverkeyfloat("phy_stopspeed") / flFriction) * flApplyFriction;
} else {
flFriction = 1 - move_time * flApplyFriction;
}
flFriction = 1 - move_time * flApplyFriction;
}
if (flFriction < 0) {
@ -424,7 +421,9 @@ PMoveCustom_Acceleration(float move_time, float premove)
return;
}
} else {
vecWishVel = v_forward * input_movevalues[0] + v_right * input_movevalues[1];
vecWishVel = v_forward * input_movevalues[0];
vecWishVel += v_right * input_movevalues[1];
vecWishVel += v_up * input_movevalues[2];
wish_dir = normalize(vecWishVel);
wish_speed = serverkeyfloat("phy_noclipspeed");
PMoveCustom_AccelNoclip(move_time, premove, wish_dir, wish_speed);
@ -450,21 +449,16 @@ PMoveCustom_Acceleration(float move_time, float premove)
wish_dir = normalize(vecWishVel);
wish_speed = vlen(vecWishVel);
if (wish_speed > self.maxspeed) {
if (serverkeyfloat("phy_nospeedcap") == 0 && wish_speed > self.maxspeed) {
wish_speed = self.maxspeed;
}
if (self.movetype == MOVETYPE_NOCLIP) {
self.flags &= ~FL_ONGROUND;
self.velocity = wish_dir * wish_speed;
if (self.flags & FL_ONLADDER) {
PMoveCustom_AccelLadder(move_time, premove, wish_dir, wish_speed);
} else if (self.flags & FL_ONGROUND) {
PMoveCustom_AccelFriction(move_time, premove, wish_dir, wish_speed);
} else {
if (self.flags & FL_ONLADDER) {
PMoveCustom_AccelLadder(move_time, premove, wish_dir, wish_speed);
} else if (self.flags & FL_ONGROUND) {
PMoveCustom_AccelFriction(move_time, premove, wish_dir, wish_speed);
} else {
PMoveCustom_AccelGravity(move_time, premove, wish_dir, wish_speed);
}
PMoveCustom_AccelGravity(move_time, premove, wish_dir, wish_speed);
}
}
@ -600,10 +594,11 @@ PMoveCustom_Move(void)
break;
}
/* there's something in the way, so let's try to bounce off of it, or step up */
saved_plane = trace_plane_normal;
move_time -= move_time * trace_fraction;
if (move_time) {
if (move_time > 0.0) {
/* step up if we can */
trace_endpos = self.origin;
@ -622,7 +617,7 @@ PMoveCustom_Move(void)
dest = trace_endpos + (self.velocity * move_time);
dest += (self.basevelocity * move_time);
dest[2] = trace_endpos[2]; /*only horizontally*/
/* clear base-velocity */
self.basevelocity = [0,0,0];
@ -630,7 +625,7 @@ PMoveCustom_Move(void)
tracebox(trace_endpos, self.mins, self.maxs, dest, MOVE_NORMAL, self);
/* if we got anywhere, make this raised-step move count */
if (trace_fraction == 1.0f) {
if (trace_fraction >= 1.0f) {
float fwfrac = trace_fraction;
vector fwplane = trace_plane_normal;
@ -641,10 +636,12 @@ PMoveCustom_Move(void)
if (trace_fraction < 1.0 && trace_plane_normal[2] > 0.7f) {
move_time -= move_time * fwfrac;
/* bounce off the ceiling */
if (roof_fraction < 1) {
PMoveCustom_Rebound(roof_plane_normal);
}
if (trace_fraction < 1) {
PMoveCustom_Rebound(trace_plane_normal);
} else if (fwfrac < 1) {
@ -710,6 +707,20 @@ PMoveCustom_RunPlayerPhysics(entity target)
if (self.maxspeed <= 0)
self.maxspeed = 240;
bool flying = ((target.movetype == MOVETYPE_NOCLIP) || (target.movetype == MOVETYPE_FLY));
if (flying == true) {
/* move camera up (noclip, fly) when holding jump */
if (input_buttons & INPUT_BUTTON2) {
input_movevalues[2] = 240;
}
/* move camera down (noclip, fly) when holding crouching */
if (input_buttons & INPUT_BUTTON8) {
input_movevalues[2] = -240;
}
}
#ifdef CUSTOMPLAYERPHYSICS
/* call accelerate before and after the actual move,
* with half the move each time. this reduces framerate dependence.
@ -726,8 +737,9 @@ PMoveCustom_RunPlayerPhysics(entity target)
self.angles[0] *= -0.333;
#ifdef CUSTOMPLAYERPHYSICS
/* activate any SOLID_TRIGGER entities */
touchtriggers();
/* activate any SOLID_TRIGGER entities, when not in noclip anyway */
if (self.movetype != MOVETYPE_NOCLIP)
touchtriggers();
#endif
setorigin(self, self.origin);
@ -747,7 +759,7 @@ PMoveCustom_RunCrouchPhysics(entity target)
} else {
// If we aren't holding down duck anymore and 'attempt' to stand up, prevent it
if (target.flags & FL_CROUCHING) {
if (PMove_IsStuck(target, [0,0,36], PHY_HULL_MIN, PHY_HULL_MAX) == FALSE) {
if (PMove_IsStuck(target, [0,0,36], PHY_HULL_MIN, PHY_HULL_MAX) == false) {
target.flags &= ~FL_CROUCHING;
iFixCrouch = TRUE;
}
@ -764,7 +776,7 @@ PMoveCustom_RunCrouchPhysics(entity target)
if (iFixCrouch && PMove_IsStuck(target, [0,0,0], PHY_HULL_MIN, PHY_HULL_MAX)) {
for (int i = 0; i < 36; i++) {
target.origin[2] += 1;
if (PMove_IsStuck(target, [0,0,0], target.mins, target.maxs) == FALSE) {
if (PMove_IsStuck(target, [0,0,0], target.mins, target.maxs) == false) {
break;
}
}

View File

@ -99,3 +99,5 @@ int Sound_GetID(string sndDef);
/** Server-side only: Play a sentences.txt entry on a given entity. */
void Sound_Speak(entity targetEntity, string sentencesEntry);
#endif
void Sound_DebugList();

View File

@ -67,6 +67,8 @@ Sound_Init(void)
SoundSource_Init();
precache_sound("misc/missing.wav");
precache_sound("misc/null.wav");
precache_sound("common/null.wav");
print("SoundDef initialized.\n");
}
@ -459,6 +461,7 @@ Sound_Precache(string shader)
print("^1no soundDef found for ");
print(shader);
print("\n");
g_sounds_count--;
search_end(sh);
return -1;
@ -943,3 +946,15 @@ SoundSource_Init(void)
}
fclose(manifestFile);
}
/** Called by listSoundDef */
void
Sound_DebugList(void)
{
for (int i = 0; i < g_sounds_count; i++) {
print(sprintf("%i: %s (%i samples)\n", i, g_sounds[i].name, g_sounds[i].sample_count));
}
print(sprintf("\t%i total soundDef loaded\n", g_sounds_count));
}