WIP pmove, AI, etc. changes

This commit is contained in:
Marco Cawthorne 2024-04-22 15:11:12 -07:00
parent d5053299dc
commit 822a7221b2
Signed by: eukara
GPG Key ID: CE2032F0A2882A22
132 changed files with 5198 additions and 1950 deletions

View File

@ -1,10 +1,18 @@
# Bots
Bots are handled by BotLib, located under `src/botlib` in the directory tree.
Bots are CPU controlled opponents. They can be useful for development, debugging but can also fun to play with.
They're fake clients, traversing the level, and acting upon objectives they either figure out themselves, or are told to to act a certain way.
We encourage any multiplayer game to support them, because they often also fill in the function of balancing teams. There's a whole slew of benefits of supporting bots, and players will generally thank you for including them.
## Technical Info
Bots are handled by BotLib, located under `src/botlib/` in the source tree.
Nuclide's BotLib takes some inspiration from **Quake III Arena** its bots, but shares no code or specific ideas or implementations. We do not use **AAS** for navigation, we leverage the route/pathfinding system **FTEQW** provides. Bots also share some code with regular NPC/Monster type entities through the use of the NSNavAI class.
Games are allowed to handle how they want to integrate bots themselves, but for development purposes there are ways to force bots to spawn.
Games are allowed to handle how they want to integrate bots themselves, but for development purposes there are ways to force bots to spawn also.
# Bot profiles
@ -52,4 +60,38 @@ Force reset bots current trajectory and goals.
# Bot Console Variables
See `platform/cvars.cfg` under the `// bots` section.
## bot_enable
Enable (1) or disable (0) usage of bots in the game. Default is 1.
## bot_pause
Enable (1) or disable (0) an interrupt for the Bot AIs thinking. Default is 0.
## bot_noChat
Enable (1) or disable (0) a suppression of any bot chatter. Default is 0.
## bot_fastChat
Enable (1) or disable (0) bot chatter that does not stop other inputs. Default is 0.
## bot_debug
Enable (1) or disable (0) bot debug features that otherwise won't work. Default is 0.
## bot_developer
Enable (1) or disable (0) bot debug text in console. Default is 0.
## bot_minClients
When set, ensures to fill the server with this many players/bots. Default is -1.
## bot_aimless
Enable (1) or disable (0) bot not knowing where to go. Will keep generating a new place to walk to.
## bot_crouch
Enable (1) or disable (0) the forcing of bots crouching down.
## bot_walk
Enable (1) or disable (0) the restriction of bots to walking speed.
## bot_prone
Enable (1) or disable (0) the forcing of bots to crawl/prone.
## bot_dont_shoot
Enable (1) or disable (0) bot pacifist mode.

View File

@ -192,6 +192,8 @@
[info_intermission](@ref info_intermission)
[info_landmark](@ref info_landmark)
[info_node](@ref info_node)
[info_node_air](@ref info_node_air)
@ -286,6 +288,8 @@
[prop_physics](@ref prop_physics)
[prop_physics_multiplayer](@ref prop_physics_multiplayer)
[prop_rope](@ref prop_rope)
[prop_static](@ref prop_static)
@ -296,6 +300,16 @@
[random_trigger](@ref random_trigger)
[script_brushmodel](@ref script_brushmodel)
[script_model](@ref script_model)
[script_origin](@ref script_origin)
[script_struct](@ref script_struct)
[script_vehicle](@ref script_vehicle)
[scripted_sentence](@ref scripted_sentence)
[scripted_sequence](@ref scripted_sequence)

74
Documentation/MapC.md Normal file
View File

@ -0,0 +1,74 @@
# MapC Scripting
**Notice: This is an uncomitted document and is subject to change.**
Powered by the engine's multi-progs capability, maps can run their own isolated logic.
This is inspired by the original MapC effort by [Team Fortress Software/Valve](https://web.archive.org/web/19990221213004/http://www.teamfortress.com:80/tfii/mc2.html) that never got off the ground.
Ritual's ÜberTools for Quake III also had a scripting system for each map, this is comparable to that also. The same extends to the **GSC** scripts found in Call of Duty that each map has.
If you're curious about use-cases, you should make yourself familar with what those games do.
## MapC versus QuakeC
MapC is basically a superset of QuakeC.
You essentially write valid SSQC, but there's extra helper functions that you can use to communicate with entities from the server-side progs. Concepts that are alien to regular QuakeC code.
If a `mapscript.dat` is next to the map of the same name (`mapscript.bsp`), it will be included into the game.
An example source file from Nuclide's `base/test_maps.pk3dir/maps/mapscript.mapC`:
```cpp
#pragma PROGS_DAT "mapscript.dat"
#include "../../../src/server/mapC.h"
void main()
{
entity spawnPoint = spawnClass("info_player_start", [0, 0, 128]);
spawnPoint.angles = [0, random(-180, 180), 0];
spawnPoint.targetname = "SPSpawn";
spawnPoint = spawnClass("info_player_deathmatch", [0, 0, 128]);
spawnPoint.angles = [0, random(-180, 180), 0];
spawnPoint.targetname = "MPSpawn";
}
```
Here you can see that while we stick to the `entity` base type, we do get to use a new function to spawn entities: `spawnclass(string className, desiredPosition)`.
This ensures that the server-side progs gets to load all available [EntityDef](EntityDef.md) based entities, as well as all internal, available, class-based entities - and sends those to our map-specific progs.
If you don't use spawnClass(), expect to not be able to use the I/O system with the entity.
To have access to all features, make sure to include `mapC.h` from Nuclide's `src/server` directory. That file will continously be updated to add more functionality.
You can compile the MapC file with fteqcc (`fteqcc mapscript.mapC`) to receive `mapscript.dat`.
Like with regular QuakeC progs, you only have to include the resulting .dat with your game - although we encourage you to release the sources to all progs for modders and tinkerers to enjoy. It's also a way for users to support the game themselves in case you're no longer able to support it.
## Use cases, benefits
When it comes to managing the complexity of events in games like the Call of Duty series, this is a desired substitute to hundreds (sometimes thousands) of entities.
Boxing the map-specific logic also aids portability. With less dependence on Nuclide or other internal functions to organize and schedule most of its logic, forward compatibility is easily achieved.
The design has been proven across dozens of games within the Call of Duty series, with little to no changes - serving for both single and multiplayer logic. Managing waves of enemies, or writing entire game-modes using this type of set-up has been proven.
## Extra features over Vanilla SSQC
These extra functions are available to MapC programs:
### spawnClass(className, desiredPos)
Spawns the specified entity class name at the desired position. If the classname does not exist, it will return a new info_notnull type entity with no model or collision for you to modify.
### sendInput(targetEntity, inputName, dataString, targetActivator)
Sends an input event to an NSEntity and with a specific activator. While that can be __NULL__, this, or world most of the time - some inputs very much depend on the activator being valid within their respective contexts.
## Map-specific entities
You can bundle an [EntityDef](EntityDef.md) file with your level, like with MapC progs they have to have the same filename as the map, but with the extension ending in '**def**' (e.g. `maps/mapscript.def`).
The entities within that EntityDef file will be exclusive to that map. No other map can spawn them. If you want to make an EntityDef available to all maps, move it into the `def/` directory of your game directory.

57
Documentation/MapTypes.md Normal file
View File

@ -0,0 +1,57 @@
# Map Making
## Which Format You Should Use
That depends on the job. If you want to work with a modern format, comparable to that of a 2004 game engine and beyond, any variant of Quake III Arena's BSP format can do.
We aim to support everything equally.
For a more authentic, 1990s experience you may want to use Quake II's format instead.
We have our own variant of the BSP format, which can be compiled by using [vmap](VMap.md).
### Quake BSP
This is the default format that all the Quake tools, such as [ericw-tools](https://ericwa.github.io/ericw-tools/) compile into. If you exceed limits, they generally will generate a **"BSP2"** file, which is something our engine also understands. The original engine and format only did monochrome color. This is no issue any longer because modern compilers output so called **lit** files, which contain colored lightmaps externally. If a Quake engine supports colored lights, they'll usually load them automatically.
However, creating non-planar surfaces or changing the lightmap quality on individual surfaces is not supported in this format. If you want to use features such as crouching or proning you have to compile your map with **BSPX** extensions. Other formats also include more features, which can help optimise the network and rendering performance of a level. So use of this format is discouraged by us.
You can totally use it if you're going for a certain aesthetic, just be aware of its limitations. You cannot optimise levels beyond a certain point due to a lack of area-portals which were introduced with Quake II BSP.
### Quake II BSP
A better choice over Quake's standard BSP format. These support area-portals and proper detail brushes can help optimise the level even further.
### Quake III Arena BSP
**The recommended format.** Support for everything Quake II's BSP does, but you can now put a lot of detailed geometry into so called triangle soup, and design your own content volumes (beyond water, lava, slime), and surface flags (make bullets ricochet, or leak water) - make use of curved surfaces, massive maps with terrain and texture blending. Support for different lightmap scales per surface, and alternative vertex-lit levels can also give you tigter controls about lighting performance and visual fidelity.
### VMAP compiled BSP
Our own version of the Quake III Arena BSP format. It supports a bunch of new things.
The compiler doesn't read .shader files from `scripts/` but instead `.mat` files alongside the textures within the textures directory, as well as a custom patch/curve format.
Only use this if you really, really want to use the things we developed. You will have a smoother experience with most other formats right now.
### Other Formats
While the engine can read other formats, such as BSP30 and beyond - please ensure you do have the rights to use the tools in such fashion. For example, for developers coming from the Half-Life SDK you are not allowed to use compilers and versions deriving from the original sources to make maps for Nuclide based projects. You will have to negotiate a license with Valve or use a free-software tool such as [ericw-tools](https://ericwa.github.io/ericw-tools/).
## Recommended Tools
We don't require you to use WorldSpawn or VMAP. You can use any of the above formats, and whatever editor you like to use to get the job done.
Here's a list of popular editors we've seen people use successfully:
- NetRadiant-Custom
- TrenchBroom
- NetRadiant
- GtkRadiant
- QuArK
- JACK (proprietary)
However we do not provide support for any of them. Please talk to the developers of the respective tools if you're experiencing issues. First ensure that you're able to make levels for your target format.
For example, create an example map for Quake, test it in Quake and then copy it into your Nuclide directory after verifying it works and that the workflow is right for you.
You may need to switch tools if you're not comfortable, and only once you're fully set and familar with the map-making toolchain should you attempt to run the maps in Nuclide.
As map-making is a complicated process, a lot of issues you can run into while making levels for Nuclide, may actually be issues with the toolchain you're using to make the map. So verify it works in the target format's game of choice first.

View File

@ -893,6 +893,7 @@ INPUT = src/ \
Documentation/Shaders/ \
Documentation/Constants.md \
Documentation/EntityDef.md \
Documentation/MapC.md \
Documentation/Surf_data.md \
Documentation/Prop_data.md \
Documentation/MapTweaks.md \

26
base/radiant.game Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<game
type="hl"
name="Nuclide"
enginepath_linux="/usr/local/games/nuclide/"
enginepath_win32="c:/vera/nuclide/"
engine_win32="fteqw.exe"
engine_linux="fteqw"
basegame="platform"
basegamename="Nuclide"
unknowngamename="Nuclide Game Directory"
default_scale="0.5"
no_patch="0"
no_bsp_monitor="0"
show_wads="0"
archivetypes="pk3"
texturetypes="tga ktx"
modeltypes="iqm"
maptypes="mapq3"
shaders="quake3"
entityclass="quake3"
entityclasstype="def"
entities="quake3"
brushtypes="quake"
patchtypes="quake3"
/>

26
base/radiiant.xml Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<project version="2.0">
<var name="vmap">"[RadiantPath]vmap" -v<cond value="[MonitorAddress]"> -connect [MonitorAddress]</cond> -game platform -fs_basepath "[EnginePath]"<cond value="[GameName]"> -fs_game [GameName]</cond></var>
<build name="Fast Fullbright">
<command>[vmap] -custinfoparms -threads 4 -samplesize 8 "[MapFile]"</command>
<command>[vmap] -vis -v -fast "[MapFile]"</command>
</build>
<build name="Fast">
<command>[vmap] -custinfoparms -threads 4 -samplesize 8 "[MapFile]"</command>
<command>[vmap] -vis -v -fast "[MapFile]"</command>
<command>[vmap] -light -custinfoparms -v -samplesize 8 -fast -threads 4 -samples 4 -shade -shadeangle 60 -patchshadows "[MapFile]"</command>
</build>
<build name="Full">
<command>[vmap] -custinfoparms -threads 4 -samplesize 8 "[MapFile]"</command>
<command>[vmap] -vis "[MapFile]"</command>
<command>[vmap] -light -custinfoparms -samplesize 8 -fast -threads 4 -samples 4 -shade -shadeangle 60 -patchshadows "[MapFile]"</command>
</build>
</build>
</project>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -12,7 +12,7 @@
* 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.
*/
*/
struct
{
@ -25,11 +25,11 @@ struct
} g_camBobVars[4], *pCamBob;
/* tilts the camera for a head-bob like effect when moving */
void
Camera_RunBob(__inout vector camera_angle)
vector
Camera_RunBob(vector camera_angle)
{
if (!autocvar(v_cambob, 1, "Enables bobbing effect for the first-person camera"))
return;
return camera_angle;
int s = (float)getproperty(VF_ACTIVESEAT);
pCamBob = &g_camBobVars[s];
@ -39,15 +39,16 @@ Camera_RunBob(__inout vector camera_angle)
speed[2] = 0.0f;
pCamBob->m_flSpeed = vlen(speed);
if (pCamBob->m_flSpeed > 330.0f)
pCamBob->m_flSpeed = 330.0f;
/* don't bother on low speeds */
if ( pCamBob->m_flSpeed < 5.0f ) {
pCamBob->m_flMove = 0.0f;
pCamBob->m_flTime = 0.0f; /* progress has halted, start anew */
return;
} else if (pSeat->m_ePlayer.flags & FL_ONGROUND && pSeat->m_ePlayer.waterlevel == 0) {
pCamBob->m_flMove = clframetime * (pCamBob->m_flSpeed * 0.01);
return camera_angle;
} else {
pCamBob->m_flMove = 0.0f;
pCamBob->m_flMove = frametime * (pCamBob->m_flSpeed * 0.01);
}
pCamBob->m_flTime = (pCamBob->m_flTime += pCamBob->m_flMove);
@ -62,14 +63,15 @@ Camera_RunBob(__inout vector camera_angle)
}
camera_angle[2] += pCamBob->m_flDelta;
return camera_angle;
}
/* applies a tilt to the camera for when we're strafing left to right */
void
Camera_StrafeRoll(__inout vector camera_angle)
vector
Camera_StrafeRoll(vector camera_angle)
{
if (!autocvar(v_camroll, 0, "Enables strafe-roll for the first-person camera"))
return;
return camera_angle;
float roll;
makevectors(camera_angle);
@ -78,4 +80,38 @@ Camera_StrafeRoll(__inout vector camera_angle)
roll *= 0.015f;
camera_angle[2] += roll;
return camera_angle;
}
vector
Camera_AddLean(vector viewAngle)
{
vector shift = anglesToRight(viewAngle);
vector output;
vector srcPos;
float heightChange;
player pl = (player)pSeat->m_ePlayer;
if (pSeat->m_iLeanDir > 0i) {
pSeat->m_flLeaning += frametime * 5;
} else if (pSeat->m_iLeanDir < 0i) {
pSeat->m_flLeaning -= frametime * 5;
} else {
pSeat->m_flLeaning = lerp(pSeat->m_flLeaning, 0.0, frametime * 10);
}
if (pSeat->m_flLeaning > 1.0) {
pSeat->m_flLeaning = 1.0f;
}
if (pSeat->m_flLeaning < -1.0) {
pSeat->m_flLeaning = -1.0f;
}
heightChange = cos(pSeat->m_flLeaning) * 4;
srcPos = pl.GetEyePos();
output = shift * (pSeat->m_flLeaning * 15.0);
tracebox(srcPos, [-8,-8,-8], [8,8,8], srcPos + output, MOVE_NORMAL, pl);
return output * trace_fraction + (shift * -1.0) + [0, 0, heightChange];
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2021 Marco Cawthorne <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -12,11 +12,18 @@
* 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.
*/
*/
var float autocvar_v_bob = 0.01f;
var float autocvar_v_bobcycle = 1.0f;
var float autocvar_v_bobup = 0.5f;
#define BOB_STRENGTH 0.02
#define BOB_CYCLE 1.0
#define BOB_UP 0.60
var vector autocvar_bg_bobAmplitudeDucked = [0.0075, 0.0065, 0.0000];
var vector autocvar_bg_bobAmplitudeProne = [0.02, 0.005, 0.0000];
var vector autocvar_bg_bobAmplitudeSprinting = [0.02, 0.014, 0.0000];
var vector autocvar_bg_bobAmplitudeStanding = [0.007, 0.007, 0.0000];
var float autocvar_bg_bobMax = 8.0;
var float autocvar_player_sprintCameraBob = 0.5;
struct
{
@ -27,6 +34,9 @@ struct
float m_flBobCycle;
float m_flBobCycle2;
float m_flSpeed;
float m_flViewBob;
float m_flViewBob2;
} g_viewBobVars[4], *pViewBob;
@ -45,13 +55,20 @@ Viewmodel_CalcBob(void)
float var_bob;
float var_cycle;
float var_up;
bool isSprinting = pSeat->m_ePlayer.vv_flags & VFL_SPRINTING;
bool isCrouching = pSeat->m_ePlayer.vv_flags & VFL_CROUCHING;
var_bob = autocvar_v_bob;
var_cycle = autocvar_v_bobcycle;
var_up = autocvar_v_bobup;
// if (pSeatLocal->m_iSprinting && vlen(pSeat->m_vecPredictedVelocity) > 240)
// isSprinting = true;
pViewBob->m_flBobTime += clframetime;
pViewBob->m_flBobTime2 += clframetime;
var_bob = BOB_STRENGTH;
var_cycle = BOB_CYCLE;
var_up = BOB_UP;
if (isSprinting)
var_cycle *= autocvar_player_sprintCameraBob;
pViewBob->m_flBobTime += frametime;
pViewBob->m_flBobCycle = pViewBob->m_flBobTime - (int)(pViewBob->m_flBobTime / var_cycle) * var_cycle;
pViewBob->m_flBobCycle /= var_cycle;
@ -66,10 +83,11 @@ Viewmodel_CalcBob(void)
pViewBob->m_flSpeed = vlen(vecVel);
flBob = pViewBob->m_flSpeed * var_bob;
flBob = flBob * 0.3 + flBob * 0.7 * sin(pViewBob->m_flBobCycle);
pViewBob->m_flBob = bound(-7, flBob, 4);
flBob = flBob * sin(pViewBob->m_flBobCycle);
pViewBob->m_flBob = flBob;
/* BOB2, which is half the cycle of bob1 */
pViewBob->m_flBobTime2 += frametime;
pViewBob->m_flBobCycle2 = pViewBob->m_flBobTime2 - (int)(pViewBob->m_flBobTime2 / (var_cycle * 0.5f)) * (var_cycle * 0.5f);
pViewBob->m_flBobCycle2 /= (var_cycle * 0.5f);
@ -79,12 +97,26 @@ Viewmodel_CalcBob(void)
pViewBob->m_flBobCycle2 = MATH_PI + MATH_PI * (pViewBob->m_flBobCycle2 - var_up)/(1.0 - var_up);
}
flBob = pViewBob->m_flSpeed * var_bob;
flBob = flBob * 0.3 + flBob * 0.7 * sin(pViewBob->m_flBobCycle2);
pViewBob->m_flBob2 = bound(-7, flBob, 4);
flBob = pViewBob->m_flSpeed * (var_bob * 0.5);
flBob = flBob * cos(pViewBob->m_flBobCycle2);
pViewBob->m_flBob2 = flBob;
/* make sure it's adjusted for scale */
pViewBob->m_flBob *= autocvar_cg_viewmodelScale;
if (isSprinting) {
pViewBob->m_flViewBob2 = pViewBob->m_flBob2 * autocvar_bg_bobAmplitudeSprinting[0] * 25.0f;
pViewBob->m_flViewBob = pViewBob->m_flBob * autocvar_bg_bobAmplitudeSprinting[1] * 25.0f;
pViewBob->m_flBob2 *= autocvar_bg_bobAmplitudeSprinting[0] * 20.0;
pViewBob->m_flBob *= autocvar_bg_bobAmplitudeSprinting[1] * 20.0;
} else if (isCrouching) {
pViewBob->m_flViewBob2 = pViewBob->m_flBob2 * autocvar_bg_bobAmplitudeDucked[0] * 25.0f;
pViewBob->m_flViewBob = pViewBob->m_flBob * autocvar_bg_bobAmplitudeDucked[1] * 25.0f;
pViewBob->m_flBob2 *= autocvar_bg_bobAmplitudeDucked[0] * 20.0;
pViewBob->m_flBob *= autocvar_bg_bobAmplitudeDucked[1] * 20.0;
} else {
pViewBob->m_flViewBob2 = pViewBob->m_flBob2 * autocvar_bg_bobAmplitudeStanding[0] * 25.0f;
pViewBob->m_flViewBob = pViewBob->m_flBob * autocvar_bg_bobAmplitudeStanding[1] * 25.0f;
pViewBob->m_flBob2 *= autocvar_bg_bobAmplitudeStanding[0] * 20.0;
pViewBob->m_flBob *= autocvar_bg_bobAmplitudeStanding[1] * 20.0;
}
}
void
@ -95,13 +127,18 @@ Viewmodel_ApplyBob(entity gun)
float sintime;
float strength;
gun.angles[2] = -pViewBob->m_flBob;
float kickUp;
//gun.angles[2] = pViewBob->m_flBob2 * -2.0f;
gun.angles[2] = pViewBob->m_flViewBob * 4.0f;
kickUp = pViewBob->m_flViewBob2 * 4.0f;
vector angmod = [0,0,0];
angmod[0] -= pViewBob->m_flBob2 * 0.5f;
angmod[1] += pViewBob->m_flBob * 2.5f;
angmod[2] += pViewBob->m_flBob * 3.0f;
gun.angles += angmod * 1.5f;
angmod[0] = pViewBob->m_flViewBob2 + kickUp;
angmod[1] = pViewBob->m_flViewBob;
//angmod[2] += pViewBob->m_flBob * 3.0f;
gun.angles += angmod;
/* sway with speed */
sintime = sin(time);
@ -111,19 +148,19 @@ Viewmodel_ApplyBob(entity gun)
strength = 240;
strength = 240 - strength;
strength *= 0.005f;
strength *= 0.01f;
#ifdef WASTES
float sprint;
if (pSeatLocal->m_iSprinting && vlen(pSeat->m_vecPredictedVelocity) > 240) {
pSeatLocal->m_flSprintLerp = bound(0.0f, pSeatLocal->m_flSprintLerp + clframetime, 1.0f);
if (pSeat->m_ePlayer.vv_flags & VFL_SPRINTING) {
pSeat->m_flSprintLerp = bound(0.0f, pSeat->m_flSprintLerp + clframetime, 1.0f);
} else {
pSeatLocal->m_flSprintLerp = bound(0.0f, pSeatLocal->m_flSprintLerp - clframetime, 1.0f);
pSeat->m_flSprintLerp = bound(0.0f, pSeat->m_flSprintLerp - clframetime, 1.0f);
}
sprint = 20 * pSeatLocal->m_flSprintLerp;
sprint = 20 * pSeat->m_flSprintLerp;
gun.angles[0] += sprint;
gun.angles[1] += sprint + (sprint * pViewBob->m_flBob) * 0.25f;
#ifdef WASTES
if (pSeat->m_ePlayer.gflags & GF_IS_HEALING) {
pSeatLocal->m_flHealLerp = bound(0.0f, pSeatLocal->m_flHealLerp + clframetime, 1.0f);
} else {
@ -135,6 +172,31 @@ Viewmodel_ApplyBob(entity gun)
gun.angles[0] += strength * sintime;
gun.angles[1] += strength * sintime;
gun.angles[2] += strength * sintime;
//gun.angles[2] += strength * sintime;
gun.origin += [0,0,-1];
makevectors(g_view.GetCameraAngle());
gun.origin += v_forward * cvar("cl_gunx");
gun.origin += v_right * cvar("cl_guny");
gun.origin += v_up * cvar("cl_gunz");
/* lower gun when moving */
if (pViewBob->m_flSpeed > 10.0) {
gun.origin += (v_up * -pViewBob->m_flSpeed * 0.005f);
gun.origin += (v_right * -pViewBob->m_flSpeed * 0.005f);
}
}
vector
Camera_AddCamBob(vector cameraAngle)
{
vector angmod = g_vec_null;
makevectors(cameraAngle);
angmod = (pViewBob->m_flBob2 * -v_up);
angmod += (pViewBob->m_flBob * -v_right);
return angmod;
}

View File

@ -37,7 +37,7 @@ GameRules::LevelDecodeParms(NSClientPlayer pp)
pl.activeweapon = parm11;
pl.flags = parm64;
if (pl.flags & FL_CROUCHING) {
if (pl.vv_flags & VFL_CROUCHING) {
setsize(pl, VEC_CHULL_MIN, VEC_CHULL_MAX);
} else {
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);

View File

@ -47,6 +47,7 @@ SingleplayerRules::PlayerSpawn(NSClientPlayer pl)
pl.viewzoom = 1.0;
pl.model = "models/player.mdl";
setmodel(pl, pl.model);
pl.AddEffects(EF_NOSHADOW);
setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX);
pl.velocity = [0,0,0];

View File

@ -1,10 +1,8 @@
#includelist
player.qc
weapon_common.h
weapons.h
flags.h
fx_blood.qc
fx_corpse.qc
weapons.qc
weapon_common.qc
#endlist

View File

@ -35,6 +35,7 @@ class player:NSClientPlayer
virtual void(float,float) ReceiveEntity;
virtual void(void) PredictPreFrame;
virtual void(void) PredictPostFrame;
virtual void(void) UpdateAliveCam;
#else
virtual void(void) EvaluateEntity;
virtual float(entity, float) SendEntity;
@ -42,6 +43,41 @@ class player:NSClientPlayer
};
#ifdef CLIENT
void Shake_Update(NSClientPlayer);
vector Camera_RunBob(vector);
vector Camera_StrafeRoll(vector);
vector Camera_AddCamBob(vector);
vector Camera_AddLean(vector);
void View_DisableViewmodel(void);
void
player::UpdateAliveCam(void)
{
vector cam_pos = GetEyePos();
g_view.SetCameraAngle(view_angles);
g_view.SetCameraOrigin(cam_pos + Camera_AddCamBob(view_angles) + Camera_AddLean(view_angles));
if (vehicle) {
NSVehicle veh = (NSVehicle)vehicle;
if (veh.UpdateView)
veh.UpdateView();
} else if (health) {
if (autocvar_pm_thirdPerson == TRUE) {
makevectors(view_angles);
vector vStart = [pSeat->m_vecPredictedOrigin[0], pSeat->m_vecPredictedOrigin[1], pSeat->m_vecPredictedOrigin[2] + 16] + (v_right * 4);
vector vEnd = vStart + (v_forward * -48) + [0,0,16] + (v_right * 4);
traceline(vStart, vEnd, FALSE, this);
g_view.SetCameraOrigin(trace_endpos + (v_forward * 5));
}
}
Shake_Update(this);
g_view.AddPunchAngle(punchangle);
}
/*
=================
player::ReceiveEntity

View File

@ -93,8 +93,10 @@ do
KEY_MAXS="$(cat /tmp/def_maxs)"
KEY_USAGE="$(cat /tmp/def_usage)"
KEY_MODEL="$(cat /tmp/def_model)"
# reset defaults
printf -- "" > "/tmp/def_name"
printf -- "" > "/tmp/def_color"
printf -- "1 0 1" > "/tmp/def_color"
printf -- "" > "/tmp/def_mins"
printf -- "" > "/tmp/def_mins"
printf -- "" > "/tmp/def_maxs"

View File

@ -180,6 +180,12 @@ varying vec3 norm;
discard;
#endif
#if r_skipDetail == 0
#if defined(UPPERLOWER)
diffuse_f.rgb *= (texture2D(s_upper, tex_c * 4.0).rgb + 0.5);
#endif
#endif
#ifdef FAKESHADOWS
diffuse_f.rgb *= ShadowmapFilter(s_shadowmap, vtexprojcoord);
#endif
@ -234,13 +240,6 @@ varying vec3 norm;
if (alpha > 1.0)
alpha = 1.0;
#if r_skipDetail == 0
#if defined(UPPERLOWER)
diffuse_f.rgb *= (texture2D(s_upper, tex_c * 4.0).rgb + 0.5);
#endif
#endif
gl_FragColor = vec4(fog3(diffuse_f.rgb), alpha);
}
#endif

View File

@ -0,0 +1,36 @@
//======= Copyright (c) 2023 Vera Visions LLC. All rights reserved. =======
//
// Purpose:
//
// Unlit surface.
//==============================================================================
!!ver 110
!!permu FOG
!!samps diffuse
#include "sys/defs.h"
#include "sys/fog.h"
varying vec2 tex_c;
#ifdef VERTEX_SHADER
void main ()
{
tex_c = v_texcoord;
gl_Position = ftetransform();
}
#endif
#ifdef FRAGMENT_SHADER
void main ()
{
vec4 d_f = vec4(1.0, 1.0, 1.0, 1.0) - texture2D( s_diffuse, tex_c );
if (d_f.a > 0.5) {
discard;
}
gl_FragColor = fog4( d_f );
}
#endif

View File

@ -1,4 +1,4 @@
entityDef bot
{
spawnclass NSBot
"spawnclass" "NSBot"
}

View File

@ -0,0 +1,4 @@
entityDef player
{
"spawnclass" "NSClientPlayer"
}

View File

@ -1,26 +1,26 @@
entityDef info_player_start
{
editor_mins "-16 -16 -36"
editor_maxs "16 16 36"
editor_description "Singleplayer Spawn Point"
spawnclass NSSpawnPoint
"editor_mins" "-16 -16 -36"
"editor_maxs" "16 16 36"
"editor_description" "Singleplayer Spawn Point"
"editor_color" "1 0 0"
"spawnclass" "NSSpawnPoint"
}
entityDef info_player_deathmatch
{
editor_mins "-16 -16 -36"
editor_maxs "16 16 36"
editor_description "Deathmatch Spawn Point"
spawnclass NSSpawnPoint
"editor_mins" "-16 -16 -36"
"editor_maxs" "16 16 36"
"editor_description" "Deathmatch Spawn Point"
"editor_color" "1 0 0"
"spawnclass" "NSSpawnPoint"
}
entityDef info_player_coop
{
editor_mins "-16 -16 -36"
editor_maxs "16 16 36"
editor_description "Cooperative Spawn Point"
spawnclass NSSpawnPoint
"editor_mins" "-16 -16 -36"
"editor_maxs" "16 16 36"
"editor_description" "Cooperative Spawn Point"
"editor_color" "1 0 0"
"spawnclass" "NSSpawnPoint"
}

View File

@ -141,7 +141,7 @@ seta con_notifylines "0"
// set a default locale, because the engine won't
seta lang "en_us"
// external texture formats that we recognize
seta r_imageextensions "vtf tga bmp pcx png jpg"
seta r_imageextensions "bmp dds jpg ktx pcx png tga vtf"
// store screenshots in TrueVision Targa by default
seta scr_sshot_type "tga"
// don't force music loops

View File

@ -80,6 +80,10 @@ class NSBot:player
virtual botstate_t(void) GetState;
virtual botpersonality_t(void) GetPersonality;
virtual float GetForwardSpeed(void);
virtual float GetSideSpeed(void);
virtual float GetBackSpeed(void);
virtual void(string) ChatSay;
virtual void(string) ChatSayTeam;
virtual void(void) Pain;
@ -109,9 +113,9 @@ entity Bot_AddQuick(void);
void
Bot_RandomColormap(NSBot target)
{
vector x = hsv2rgb(random() * 360, 100, 100);
vector x = hsvToRGB(random() * 360, 100, 100);
float top = x[2] + (x[1] << 8) + (x[0] << 16);
x = hsv2rgb(random() * 360, 100, 100);
x = hsvToRGB(random() * 360, 100, 100);
float bottom = x[2] + (x[1] << 8) + (x[0] << 16);
forceinfokey(target, "topcolor", sprintf("0x%x", top));
forceinfokey(target, "bottomcolor", sprintf("0x%x", bottom));

View File

@ -14,6 +14,11 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* default client side player movement values */
var float autocvar_bot_forwardspeed = 190;
var float autocvar_bot_sidespeed = 152;
var float autocvar_bot_backspeed = 133;
botstate_t
NSBot::GetState(void)
{
@ -44,6 +49,24 @@ NSBot::GetRunSpeed(void)
return 240;
}
float
NSBot::GetForwardSpeed(void)
{
return (autocvar_bot_forwardspeed);
}
float
NSBot::GetSideSpeed(void)
{
return (autocvar_bot_sidespeed);
}
float
NSBot::GetBackSpeed(void)
{
return (autocvar_bot_backspeed);
}
void
NSBot::RouteClear(void)
{
@ -79,7 +102,7 @@ NSBot::UseButton(void)
pos[0] = e.absmin[0] + (0.5 * (e.absmax[0] - e.absmin[0]));
pos[1] = e.absmin[1] + (0.5 * (e.absmax[1] - e.absmin[1]));
pos[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2]));
dist = vlen(origin - pos);
dist = distanceSquared(origin, pos);
if (dist < bestDist) {
bestDist = dist;
@ -144,9 +167,7 @@ NSBot::SeeThink(void)
continue;
/* first, is the potential enemy in our field of view? */
makevectors(v_angle);
vector v = normalize(w.origin - origin);
flDot = v * v_forward;
flDot = vectorNormalize(w.origin - origin) * anglesToForward(v_angle);
if (flDot < 90/180)
continue;
@ -200,7 +221,7 @@ NSBot::CheckRoute(void)
if (m_iCurNode >= 0) {
/* if a node is flagged as jumpy, jump! */
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_JUMP) {
//input_buttons |= INPUT_BUTTON2;
//input_buttons |= INPUT_JUMP;
velocity = Route_GetJumpVelocity(origin, m_pRoute[m_iCurNode].dest, gravity);
}
@ -245,16 +266,15 @@ NSBot::CheckRoute(void)
if (m_flNodeGiveup >= 1.0f || m_iCurNode <= BOTROUTE_END) {
BotEntLog("Taking too long! Giving up!");
RouteClear();
} else if (m_flNodeGiveup >= 0.5f) {
/* attempt a jump after half a second */
} else if (m_flNodeGiveup >= 0.5f) { /* attempt a jump after half a second */
/* don't bother if it's too high (we're aiming at air... */
if ((vecEndPos[2] - 32) < origin[2])
input_buttons |= INPUT_BUTTON2;
if ((vecEndPos[2] - 32) < origin[2]) {
input_buttons |= INPUT_JUMP;
}
} else {
/* entire way-link needs to be crouched. that's the law of the land */
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_CROUCH || autocvar_bot_crouch)
input_buttons |= INPUT_BUTTON8;
input_buttons |= INPUT_CROUCH;
}
}
@ -285,7 +305,7 @@ NSBot::RunAI(void)
}
/* DEVELOPER CVAR: freeze the bot */
if (autocvar_bot_stop)
if (autocvar_bot_pause)
return;
/* create our first route */
@ -344,8 +364,8 @@ NSBot::RunAI(void)
/* if we've got a path (we always should) move the bot */
if (m_iNodes) {
bool goRoute = false;
vector vecNewAngles;
vector vecDirection;
vector vecNewAngles = g_vec_null;
vector vecDirection = g_vec_null;
/* no enemy, or it isn't visible... then stare at nodes! */
if (!m_eTarget || enemyVisible == false) {
@ -369,8 +389,7 @@ NSBot::RunAI(void)
/* aim ahead if aimPos is somehow invalid */
if (aimPos == [0,0,0]) {
makevectors(angles);
aimPos = origin + v_forward * 128;
aimPos = origin + anglesToForward(angles) * 128;
}
/* lerping speed, faster when we've got a target */
@ -379,28 +398,17 @@ NSBot::RunAI(void)
else
flLerp = bound(0.0f, frametime * 30, 1.0f);
/* that's the old angle */
makevectors(v_angle);
vecNewAngles = v_forward;
/* that's actually the old angle */
vecNewAngles = anglesToForward(v_angle);
/* aimDir = new final angle */
aimDir = vectoangles(aimPos - origin);
makevectors(aimDir);
aimDir = vectorToAngles(aimPos - origin);
/* slowly lerp towards the final angle */
vecNewAngles[0] = Math_Lerp(vecNewAngles[0], v_forward[0], flLerp);
vecNewAngles[1] = Math_Lerp(vecNewAngles[1], v_forward[1], flLerp);
vecNewAngles[2] = Math_Lerp(vecNewAngles[2], v_forward[2], flLerp);
vecNewAngles = vectorLerp(vecNewAngles, anglesToForward(aimDir), flLerp);
/* make sure we're aiming tight */
v_angle = vectoangles(vecNewAngles);
v_angle[0] = Math_FixDelta(v_angle[0]);
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = Math_FixDelta(v_angle[2]);
angles[0] = Math_FixDelta(v_angle[0]);
angles[1] = Math_FixDelta(v_angle[1]);
angles[2] = Math_FixDelta(v_angle[2]);
input_angles = v_angle;
input_angles = angles = v_angle = vectorToAngles(vecNewAngles);
bool shouldWalk = autocvar_bot_walk;
@ -460,21 +468,23 @@ NSBot::RunAI(void)
ForceWeaponAttack(traceEnt.WorldSpaceCenter(), 1.0f);
}
/* now we'll set the movevalues relative to the input_angle */
/* make them walk when they need to. */
if ((m_iCurNode >= 0 && Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_WALK) || shouldWalk)
vecDirection = normalize(aimPos - origin) * GetWalkSpeed();
SetMoveSpeedScale(0.5f);
else
vecDirection = normalize(aimPos - origin) * GetRunSpeed();
SetMoveSpeedScale(1.0f);
vecDirection = vectorNormalize(aimPos - GetEyePos()) * g_pmoveVars.pm_walkspeed;
makevectors(input_angles);
input_movevalues = [v_forward * vecDirection, v_right * vecDirection, v_up * vecDirection];
input_movevalues[2] = 0;
#if 1
/* duck and stand still when our enemy seems strong */
if (m_eTarget && enemyVisible && m_eTarget.health >= 75) {
if (m_wtWeaponType == WPNTYPE_RANGED) {
input_buttons |= INPUT_BUTTON8;
input_buttons |= INPUT_CROUCH;
input_movevalues = [0,0,0];
}
}
@ -482,14 +492,14 @@ NSBot::RunAI(void)
}
/* press any buttons needed */
button0 = input_buttons & INPUT_BUTTON0; // attack
button2 = input_buttons & INPUT_BUTTON2; // jump
button3 = input_buttons & INPUT_BUTTON3; // tertiary
button4 = input_buttons & INPUT_BUTTON4; // reload
button5 = input_buttons & INPUT_BUTTON5; // secondary
button6 = input_buttons & INPUT_BUTTON6; // use
button7 = input_buttons & INPUT_BUTTON7; // unused
button8 = input_buttons & INPUT_BUTTON8; // duck
button0 = input_buttons & INPUT_PRIMARY; // attack
button2 = input_buttons & INPUT_JUMP; // jump
button3 = input_buttons & INPUT_PRONE; // prone
button4 = input_buttons & INPUT_RELOAD; // reload
button5 = input_buttons & INPUT_SECONDARY; // secondary
button6 = input_buttons & INPUT_USE; // use
button7 = input_buttons & INPUT_SPRINT; // unused
button8 = input_buttons & INPUT_CROUCH; // duck
movement = input_movevalues;
}
@ -515,9 +525,9 @@ void
NSBot::SetName(string nickname)
{
if (autocvar_bot_prefix)
forceinfokey(this, "name", sprintf("%s %s", autocvar_bot_prefix, nickname));
SetInfoKey("name", sprintf("%s %s", autocvar_bot_prefix, nickname));
else
forceinfokey(this, "name", nickname);
SetInfoKey("name", nickname);
}
void
@ -525,7 +535,7 @@ NSBot::NSBot(void)
{
classname = "player";
targetname = "_nuclide_bot_";
forceinfokey(this, "*bot", "1");
SetInfoKey("*bot", "1");
}
void

View File

@ -30,8 +30,8 @@ NSBot::Pain(void)
/* make this pain our new enemy! */
if (g_dmg_eAttacker && g_dmg_eAttacker != this) {
float enemydist = vlen(origin - m_eTarget.origin);
float newdist = vlen(origin - g_dmg_eAttacker.origin);
float enemydist = distanceSquared(origin, m_eTarget.origin);
float newdist = distanceSquared(origin, g_dmg_eAttacker.origin);
if (m_eTarget) {
if (newdist < enemydist) {
@ -49,7 +49,7 @@ NSBot::SetEnemy(entity en)
m_eTarget = en;
if (m_eTarget) {
m_flEnemyDist = vlen(origin - m_eTarget.origin);
m_flEnemyDist = distanceSquared(origin, m_eTarget.origin);
} else {
m_flEnemyDist = -1;
}
@ -150,7 +150,7 @@ BotLib_Alert(vector pos, float radius, float t)
for (entity w = world; (w = find(w,::targetname, "_nuclide_bot_"));) {
/* out of radius */
if (vlen(pos - w.origin) > radius)
if (distance(pos, w.origin) > radius)
continue;
NSBot f = (NSBot) w;

39
src/botlib/cvars.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* for full description check the docs. */
var bool autocvar_bot_enable = true;
var bool autocvar_bot_pause = false;
var bool autocvar_bot_noChat = false;
var bool autocvar_bot_fastChat = false;
var bool autocvar_bot_debug = false;
var bool autocvar_bot_developer = false;
var int autocvar_bot_minClients = -1i;
typedef enum
{
BOTSKILL_EASY = 1,
BOTSKILL_MEDIUM,
BOTSKILL_HARD
} botskill_t;
var botskill_t autocvar_bot_skill = BOTSKILL_MEDIUM;
var bool autocvar_bot_aimless = false;
var bool autocvar_bot_crouch = false;
var bool autocvar_bot_walk = false;
var bool autocvar_bot_prone = false;
var bool autocvar_bot_dont_shoot = false;

View File

@ -14,27 +14,14 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "cvars.h"
#include "NSBot.h"
vector Route_SelectDestination( NSBot target );
var int autocvar_bot_aimless = FALSE;
var int autocvar_nav_linksize = 256;
var int autocvar_nav_radius = 8;
var bool autocvar_bot_crouch = false;
var bool autocvar_bot_walk = false;
var bool autocvar_bot_stop = false;
var bool autocvar_bot_dont_shoot = false;
var bool autocvar_bot_join_after_player = false;
var float autocvar_bot_join_delay = 0.0f;
var int autocvar_bot_quota = 0i;
var string autocvar_bot_quota_mode = "normal";
var string autocvar_bot_chatter = "normal";
var bool autocvar_bot_developer = false;
void
_BotLog(string functionName, string msg)
{
@ -59,15 +46,6 @@ _BotEntLog(string className, string functionName, float edictNum, string warnMes
@param description(...) contains a formatted string containing a description. */
#define BotEntLog(...) if (autocvar_bot_developer) _BotEntLog(classname, __FUNC__, num_for_edict(this), sprintf(__VA_ARGS__))
typedef enum
{
BOTSKILL_EASY = 1,
BOTSKILL_MEDIUM,
BOTSKILL_HARD
} botskill_t;
var botskill_t autocvar_bot_skill = BOTSKILL_MEDIUM;
var string autocvar_bot_prefix = "";
/* BotScript

0
src/botlib/entities.qc Normal file
View File

View File

@ -4,8 +4,8 @@
defs.h
profiles.qc
NSBot.qc
bot_chat.qc
bot_combat.qc
chat.qc
combat.qc
route.qc
way.qc
way_convert.qc

View File

@ -39,7 +39,7 @@ Route_SelectFarthest(float type, vector org, optional vector lastpoi = [0,0,0])
entity dest = __NULL__;
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
range = vlen(temp.origin - org);
range = distanceSquared(temp.origin, org);
if (lastpoi == temp.origin)
continue;
@ -63,7 +63,7 @@ Route_SelectNearest(float type, vector org, optional vector lastpoi = [0,0,0])
entity dest = __NULL__;
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
range = vlen(temp.origin - org);
range = distanceSquared(temp.origin, org);
if (lastpoi == temp.origin)
continue;
@ -91,7 +91,7 @@ Route_SelectNearestTeam(float type, vector org, float tt)
if (temp.team != tt)
continue;
range = vlen(tempEnt.WorldSpaceCenter() - org);
range = distanceSquared(tempEnt.WorldSpaceCenter(), org);
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
bestrange = range;
@ -116,7 +116,7 @@ Route_SelectNearestEnemyTeam(float type, vector org, float tt)
if (temp.team == tt)
continue;
range = vlen(tempEnt.WorldSpaceCenter() - org);
range = distanceSquared(tempEnt.WorldSpaceCenter(), org);
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
bestrange = range;
@ -161,14 +161,14 @@ Route_SelectRandomSpot(void)
vector
Route_SelectDestination(NSBot target)
{
CGameRules rules;
rules = (CGameRules)g_grMode;
NSGameRules rules;
rules = (NSGameRules)g_grMode;
NSEntity dest = __NULL__;
if (rules.IsTeamplay()) {
/* we have the goal item, so capture it */
if (target.flags & FL_GOALITEM) {
if (target.vv_flags & VFL_GOALITEM) {
BotLog("%s going for capture", target.netname);
dest = Route_SelectNearestTeam(BOTINFO_TEAM_GOALCAPTURE, target.origin, target.team);

View File

@ -15,6 +15,9 @@
*/
var bool autocvar_r_skipWorld = false;
var float autocvar_cg_viewZSmoothingMax = 16;
var float autocvar_cg_viewZSmoothingMin = 1;
var float autocvar_cg_viewZSmoothingTime = 0.1;
void
NSView::NSView(void)
@ -100,13 +103,13 @@ NSView::StairSmooth(void)
/* Have we gone up since last frame? */
if ((m_viewTarget.flags & FL_ONGROUND) && (endpos[2] - m_vecLastOrigin[2] > 0)) {
endpos[2] = m_vecLastOrigin[2] += (frametime * 150);
endpos[2] = m_vecLastOrigin[2] += (frametime * 1000) * autocvar_cg_viewZSmoothingTime;
if (endpos[2] > origin[2]) {
endpos[2] = origin[2];
}
if (origin[2] - endpos[2] > 18) {
endpos[2] = origin[2] - 18;
if (origin[2] - endpos[2] > autocvar_cg_viewZSmoothingMax) {
endpos[2] = origin[2] - autocvar_cg_viewZSmoothingMax;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -236,6 +236,7 @@ CMD_ListModelFramegroups(void)
print("} framegroups_e;\n");
}
/*
=================
Cmd_Parse
@ -305,10 +306,10 @@ Cmd_Parse(string sCMD)
sendevent("CallVote", "s", substring(sCMD, 9, strlen(sCMD)-9));
break;
case "+zoomin":
pSeat->m_iZoomed = TRUE;
pSeat->m_iZoomed = true;
break;
case "-zoomin":
pSeat->m_iZoomed = FALSE;
pSeat->m_iZoomed = false;
break;
case "buildcubemaps":
CMap_Build();
@ -317,22 +318,24 @@ Cmd_Parse(string sCMD)
CMD_titles_test();
break;
case "+attack2":
pSeat->m_iInputAttack2 = TRUE;
pSeat->m_iInputAttack2 = true;
break;
case "-attack2":
pSeat->m_iInputAttack2 = FALSE;
pSeat->m_iInputAttack2 = false;
break;
case "+reload":
pSeat->m_iInputReload = TRUE;
pSeat->m_iInputReload = true;
break;
case "-reload":
pSeat->m_iInputReload = FALSE;
pSeat->m_iInputReload = false;
break;
case "+activate":
case "+use":
pSeat->m_iInputUse = TRUE;
pSeat->m_iInputUse = true;
break;
case "-activate":
case "-use":
pSeat->m_iInputUse = FALSE;
pSeat->m_iInputUse = false;
break;
case "+duck":
if (autocvar_pm_crouchToggle == true)
@ -348,6 +351,46 @@ Cmd_Parse(string sCMD)
pSeat->m_bSpecInput = false;
break;
case "+prone":
pSeat->m_iInputProne = true;
break;
case "-prone":
pSeat->m_iInputProne = false;
break;
case "+sprint":
pSeat->m_iSprinting = true;
break;
case "-sprint":
pSeat->m_iSprinting = false;
break;
case "+leanleft":
pSeat->m_iLeanDir = -1;
break;
case "-leanleft":
pSeat->m_iLeanDir = 0;
break;
case "+leanright":
pSeat->m_iLeanDir = 1;
break;
case "-leanright":
pSeat->m_iLeanDir = 0;
break;
case "goprone":
pSeat->m_dForceStance = STANCE_PRONE;
break;
case "gocrouch":
pSeat->m_dForceStance = STANCE_CROUCH;
break;
case "+gostand":
if (pSeat->m_dForceStance != STANCE_DEFAULT) {
pSeat->m_dForceStance = STANCE_DEFAULT;
} else {
pSeat->m_iInputJump = true;
}
break;
case "-gostand":
pSeat->m_iInputJump = false;
break;
case "invnext":
HUD_DrawWeaponSelect_Back();
break;
@ -426,11 +469,12 @@ Cmd_Parse(string sCMD)
case "-attack_right":
pSeat->m_iInputAttack = false;
break;
case "+menu_right":
pSeat->m_iInputReload = TRUE;
pSeat->m_iInputReload = true;
break;
case "-menu_right":
pSeat->m_iInputReload = FALSE;
pSeat->m_iInputReload = false;
break;
/* client aliases for server commands */
case "addBot":
@ -495,7 +539,13 @@ Cmd_Parse(string sCMD)
case "nodeUnlink":
localcmd(sprintf("sv way unlink1 %s\n", argv(1)));
break;
case "traceMaterial":
localcmd("sv traceMaterial\n");
break;
case "bobup":
break;
case "bobdn":
break;
default:
return (false);
}
@ -522,6 +572,7 @@ Cmd_Init(void)
registercommand("listTitles");
registercommand("listClientSoundDef");
registercommand("listServerSoundDef");
registercommand("traceMaterial");
/* server commands */
registercommand("addBot");
@ -569,12 +620,22 @@ Cmd_Init(void)
registercommand("-attack");
registercommand("+attack2");
registercommand("-attack2");
registercommand("+reload");
registercommand("+reload");
registercommand("-reload");
registercommand("+activate");
registercommand("-activate");
registercommand("+use");
registercommand("-use");
registercommand("+duck");
registercommand("-duck");
registercommand("+prone");
registercommand("-prone");
registercommand("goprone");
registercommand("gocrouch");
registercommand("+gostand");
registercommand("-gostand");
registercommand("+sprint");
registercommand("-sprint");
/* voting */
registercommand("vote");

View File

@ -24,6 +24,8 @@
#include "NSView.h"
#include "NSRadar.h"
#include "crosshair.h"
#include "../shared/weapons.h"
#include "../shared/weapon_common.h"
var bool g_net_debug = false;
var bool g_cheats = false;
@ -280,6 +282,13 @@ precache_cubemap(string path)
precache_pic(strcat(path, "_up"));
}
typedef enum
{
STANCE_DEFAULT = 0,
STANCE_CROUCH = 1,
STANCE_PRONE = 2,
} movementStance_t;
struct
{
/* viewmodel stuff */
@ -340,12 +349,14 @@ struct
int m_iPrintLines;
bool m_iInputAttack;
int m_iInputAttack2;
int m_iInputReload;
int m_iInputUse;
int m_iInputDuck;
int m_iInputExtra1;
int m_iInputExtra2;
bool m_iInputAttack2;
bool m_iInputReload;
bool m_iInputUse;
bool m_iInputDuck;
bool m_iInputSprint;
bool m_iInputProne;
bool m_iInputJump;
movementStance_t m_dForceStance;
float m_flInputBlockTime;
/* fading */
@ -355,6 +366,7 @@ struct
float m_flFadeStyle;
float m_flFadeAlpha;
float m_flFadeTime;
float m_flSprintLerp;
vector m_vecFadeColor;
int m_iFadeActive;
@ -375,6 +387,10 @@ struct
bool m_bInterfaceFocused;
bool m_bSpecInput;
int m_iLeanDir;
float m_flLeaning;
int m_iSprinting;
} g_seats[4], *pSeat;
var vector g_vecMousePos;

View File

@ -235,33 +235,33 @@ EFX_SetEnvironment(int id)
void
EFX_Interpolate(int id)
{
mix.flDensity = Math_Lerp(mix.flDensity, g_efx[id].flDensity, g_flEFXTime);
mix.flDiffusion = Math_Lerp(mix.flDiffusion, g_efx[id].flDiffusion, g_flEFXTime);
mix.flGain = Math_Lerp(mix.flGain, g_efx[id].flGain, g_flEFXTime);
mix.flGainHF = Math_Lerp(mix.flGainHF, g_efx[id].flGainHF, g_flEFXTime);
mix.flGainLF = Math_Lerp(mix.flGainLF, g_efx[id].flGainLF, g_flEFXTime);
mix.flDecayTime = Math_Lerp(mix.flDecayTime, g_efx[id].flDecayTime, g_flEFXTime);
mix.flDecayHFRatio = Math_Lerp(mix.flDecayHFRatio, g_efx[id].flDecayHFRatio, g_flEFXTime);
mix.flDecayLFRatio = Math_Lerp(mix.flDecayLFRatio, g_efx[id].flDecayLFRatio, g_flEFXTime);
mix.flReflectionsGain = Math_Lerp(mix.flReflectionsGain, g_efx[id].flReflectionsGain, g_flEFXTime);
mix.flReflectionsDelay = Math_Lerp(mix.flReflectionsDelay, g_efx[id].flReflectionsDelay, g_flEFXTime);
mix.flReflectionsPan[0] = Math_Lerp(mix.flReflectionsPan[0], g_efx[id].flReflectionsPan[0], g_flEFXTime);
mix.flReflectionsPan[1] = Math_Lerp(mix.flReflectionsPan[1], g_efx[id].flReflectionsPan[1], g_flEFXTime);
mix.flReflectionsPan[1] = Math_Lerp(mix.flReflectionsPan[2], g_efx[id].flReflectionsPan[2], g_flEFXTime);
mix.flLateReverbGain = Math_Lerp(mix.flLateReverbGain, g_efx[id].flLateReverbGain, g_flEFXTime);
mix.flLateReverbDelay = Math_Lerp(mix.flLateReverbDelay, g_efx[id].flLateReverbDelay, g_flEFXTime);
mix.flLateReverbPan[0] = Math_Lerp(mix.flLateReverbPan[0], g_efx[id].flLateReverbPan[0], g_flEFXTime);
mix.flLateReverbPan[1] = Math_Lerp(mix.flLateReverbPan[1], g_efx[id].flLateReverbPan[1], g_flEFXTime);
mix.flLateReverbPan[2] = Math_Lerp(mix.flLateReverbPan[2], g_efx[id].flLateReverbPan[2], g_flEFXTime);
mix.flEchoTime = Math_Lerp(mix.flEchoTime, g_efx[id].flEchoTime, g_flEFXTime);
mix.flEchoDepth = Math_Lerp(mix.flEchoDepth, g_efx[id].flEchoDepth, g_flEFXTime);
mix.flModulationTime = Math_Lerp(mix.flModulationTime, g_efx[id].flModulationTime, g_flEFXTime);
mix.flModulationDepth = Math_Lerp(mix.flModulationDepth, g_efx[id].flModulationDepth, g_flEFXTime);
mix.flAirAbsorptionGainHF = Math_Lerp(mix.flAirAbsorptionGainHF, g_efx[id].flAirAbsorptionGainHF, g_flEFXTime);
mix.flHFReference = Math_Lerp(mix.flHFReference, g_efx[id].flHFReference, g_flEFXTime);
mix.flLFReference = Math_Lerp(mix.flLFReference, g_efx[id].flLFReference, g_flEFXTime);
mix.flRoomRolloffFactor = Math_Lerp(mix.flRoomRolloffFactor, g_efx[id].flRoomRolloffFactor, g_flEFXTime);
mix.iDecayHFLimit = Math_Lerp(mix.iDecayHFLimit, g_efx[id].iDecayHFLimit, g_flEFXTime);
mix.flDensity = lerp(mix.flDensity, g_efx[id].flDensity, g_flEFXTime);
mix.flDiffusion = lerp(mix.flDiffusion, g_efx[id].flDiffusion, g_flEFXTime);
mix.flGain = lerp(mix.flGain, g_efx[id].flGain, g_flEFXTime);
mix.flGainHF = lerp(mix.flGainHF, g_efx[id].flGainHF, g_flEFXTime);
mix.flGainLF = lerp(mix.flGainLF, g_efx[id].flGainLF, g_flEFXTime);
mix.flDecayTime = lerp(mix.flDecayTime, g_efx[id].flDecayTime, g_flEFXTime);
mix.flDecayHFRatio = lerp(mix.flDecayHFRatio, g_efx[id].flDecayHFRatio, g_flEFXTime);
mix.flDecayLFRatio = lerp(mix.flDecayLFRatio, g_efx[id].flDecayLFRatio, g_flEFXTime);
mix.flReflectionsGain = lerp(mix.flReflectionsGain, g_efx[id].flReflectionsGain, g_flEFXTime);
mix.flReflectionsDelay = lerp(mix.flReflectionsDelay, g_efx[id].flReflectionsDelay, g_flEFXTime);
mix.flReflectionsPan[0] = lerp(mix.flReflectionsPan[0], g_efx[id].flReflectionsPan[0], g_flEFXTime);
mix.flReflectionsPan[1] = lerp(mix.flReflectionsPan[1], g_efx[id].flReflectionsPan[1], g_flEFXTime);
mix.flReflectionsPan[1] = lerp(mix.flReflectionsPan[2], g_efx[id].flReflectionsPan[2], g_flEFXTime);
mix.flLateReverbGain = lerp(mix.flLateReverbGain, g_efx[id].flLateReverbGain, g_flEFXTime);
mix.flLateReverbDelay = lerp(mix.flLateReverbDelay, g_efx[id].flLateReverbDelay, g_flEFXTime);
mix.flLateReverbPan[0] = lerp(mix.flLateReverbPan[0], g_efx[id].flLateReverbPan[0], g_flEFXTime);
mix.flLateReverbPan[1] = lerp(mix.flLateReverbPan[1], g_efx[id].flLateReverbPan[1], g_flEFXTime);
mix.flLateReverbPan[2] = lerp(mix.flLateReverbPan[2], g_efx[id].flLateReverbPan[2], g_flEFXTime);
mix.flEchoTime = lerp(mix.flEchoTime, g_efx[id].flEchoTime, g_flEFXTime);
mix.flEchoDepth = lerp(mix.flEchoDepth, g_efx[id].flEchoDepth, g_flEFXTime);
mix.flModulationTime = lerp(mix.flModulationTime, g_efx[id].flModulationTime, g_flEFXTime);
mix.flModulationDepth = lerp(mix.flModulationDepth, g_efx[id].flModulationDepth, g_flEFXTime);
mix.flAirAbsorptionGainHF = lerp(mix.flAirAbsorptionGainHF, g_efx[id].flAirAbsorptionGainHF, g_flEFXTime);
mix.flHFReference = lerp(mix.flHFReference, g_efx[id].flHFReference, g_flEFXTime);
mix.flLFReference = lerp(mix.flLFReference, g_efx[id].flLFReference, g_flEFXTime);
mix.flRoomRolloffFactor = lerp(mix.flRoomRolloffFactor, g_efx[id].flRoomRolloffFactor, g_flEFXTime);
mix.iDecayHFLimit = lerp(mix.iDecayHFLimit, g_efx[id].iDecayHFLimit, g_flEFXTime);
}
void

View File

@ -22,6 +22,9 @@ Entity_EntityUpdate(float type, float new)
case ENT_ENTITY:
NSENTITY_READENTITY(NSEntity, new)
break;
case ENT_PMOVEVARS:
NSENTITY_READENTITY(NSPMoveVars, new)
break;
case ENT_ENTITYRENDERABLE:
NSENTITY_READENTITY(NSRenderableEntity, new)
break;

View File

@ -447,13 +447,7 @@ CSQC_ConsoleCommand(string sCMD)
tokenize(sCMD);
/* give us a chance to override commands */
int ret = ClientGame_ConsoleCommand();
/* successful override */
if (ret == (1))
return (1);
return Cmd_Parse(sCMD);
return (ClientGame_ConsoleCommand()) ? true : Cmd_Parse(sCMD);
}

View File

@ -14,6 +14,8 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var bool autocvar_cg_damageShake = false;
void
EV_Damage(void)
{
@ -26,6 +28,13 @@ EV_Damage(void)
iDmgTake = readint();
iDmgFlags = readint();
CSQC_Parse_Damage_New(vecDmgPos, iDmgTake, iDmgFlags);
if (autocvar_cg_damageShake) {
pSeat->m_flShakeDuration += 1.25f;
pSeat->m_flShakeAmp += iDmgTake / 16;
pSeat->m_flShakeFreq += 0.1;
pSeat->m_flShakeTime += pSeat->m_flShakeDuration;
}
}
void

View File

@ -235,10 +235,8 @@ View_DrawViewModel(void)
speed = clframetime * 20;
}
pSeat->m_vecLag[0] = Math_Lerp(pSeat->m_vecLag[0], v_forward[0], speed);
pSeat->m_vecLag[1] = Math_Lerp(pSeat->m_vecLag[1], v_forward[1], speed);
pSeat->m_vecLag[2] = Math_Lerp(pSeat->m_vecLag[2], v_forward[2], speed);
pSeat->m_vecLag = vectoangles(pSeat->m_vecLag);
pSeat->m_vecLag = vectorLerp(pSeat->m_vecLag, v_forward, speed);
pSeat->m_vecLag = vectorToAngles(pSeat->m_vecLag);
m_eViewModel.angles = pSeat->m_vecLag;
}

View File

@ -152,9 +152,7 @@ func_smokevolume::predraw(void)
func_smokevolume_cloud cloud = spawn(func_smokevolume_cloud);
setorigin(cloud, vecPos);
float r = random();
cloud.m_vecColor[0] = Math_Lerp(m_vecColor1[0], m_vecColor2[0], r);
cloud.m_vecColor[1] = Math_Lerp(m_vecColor1[1], m_vecColor2[1], r);
cloud.m_vecColor[2] = Math_Lerp(m_vecColor1[2], m_vecColor2[2], r);
cloud.m_vecColor = vectorLerp(m_vecColor1, m_vecColor2, r);
cloud.m_flMaxAlpha = m_flAlpha * fracDist;
cloud.cloudsize[0] = random(m_flSizeMin, m_flSizeMax);
cloud.cloudsize[1] = random(m_flSizeMin, m_flSizeMax);

View File

@ -90,6 +90,11 @@ server/point_trigger.qc
server/targ_speaker.qc
server/target_cdaudio.qc
server/env_global.qc
server/script_model.qc
server/script_brushmodel.qc
server/script_origin.qc
server/script_struct.qc
server/script_vehicle.qc
server/trigger_auto.qc
server/trigger_autosave.qc
server/trigger_cdaudio.qc

View File

@ -99,7 +99,6 @@ private:
float m_flDelay;
string m_strSndPressed;
string m_strSndUnpressed;
bool m_bCanTouch;
/* input/output */
@ -281,8 +280,8 @@ func_button::Respawn(void)
SetMoverPosition2(GetDirectionalPosition(GetSpawnAngles(), m_flLip));
ClearAngles();
if (health > 0) {
takedamage = DAMAGE_YES;
if (GetHealth() > 0) {
MakeVulnerable();
Death = DeathTrigger;
}
@ -298,6 +297,12 @@ func_button::Respawn(void)
SetMoverPosition2(GetMoverPosition1());
}
if (HasSpawnFlags(SF_BTT_TOUCH_ONLY) == true) {
m_bCanTouch = true;
} else {
m_bCanTouch = false;
}
m_iValue = 0;
}
@ -311,8 +316,9 @@ func_button::MoverFinishesMoving(void)
/* let's reset our button's health and mark it as shootable */
SetHealth(GetSpawnHealth());
if (GetHealth() > 0)
SetTakedamage(DAMAGE_YES);
if (GetHealth() > 0) {
MakeVulnerable();
}
if (GetMoverState() == MOVER_POS1) {
UseOutput(this, m_strOnOut);
@ -325,7 +331,6 @@ func_button::MoverFinishesMoving(void)
m_bCanTouch = true;
}
void
func_button::MoverStartsMoving(void)
{
@ -338,7 +343,7 @@ func_button::MoverStartsMoving(void)
m_iValue = 0;
if (m_strSndUnpressed) {
Sound_Play(this, CHAN_VOICE, m_strSndUnpressed);
StartSoundDef(m_strSndUnpressed, CHAN_VOICE, true);
}
}
}
@ -347,10 +352,10 @@ func_button::MoverStartsMoving(void)
void
func_button::Trigger(entity act, triggermode_t state)
{
if (GetMaster(act) == FALSE)
if (GetMaster(act) == false) {
UseOutput(act, m_strOnUseLocked);
return;
UseOutput(act, m_strOnUseLocked);
}
if (m_flNextTrigger > time) {
return;
@ -365,15 +370,17 @@ func_button::Trigger(entity act, triggermode_t state)
return;
}
if (m_strSndPressed)
Sound_Play(this, CHAN_VOICE, m_strSndPressed);
if (m_strSndPressed) {
StartSoundDef(m_strSndPressed, CHAN_VOICE, true);
}
MoveToPosition(GetMoverPosition2(), m_flSpeed);
UseOutput(act, m_strOnPressed);
UseTargets(act, TRIG_TOGGLE, m_flDelay);
if (message)
if (message) {
env_message_single(act, message);
}
SetHealth(GetSpawnHealth());
}
@ -381,21 +388,18 @@ func_button::Trigger(entity act, triggermode_t state)
void
func_button::DeathTrigger(void)
{
SetTakedamage(DAMAGE_NO);
MakeInvulnerable();
Trigger(g_dmg_eAttacker, TRIG_TOGGLE);
}
void
func_button::Touch(entity eToucher)
{
if (HasSpawnFlags(SF_BTT_TOUCH_ONLY) == false) {
if (m_bCanTouch == false) {
return;
}
if (m_bCanTouch == false)
return;
if (eToucher.movetype == MOVETYPE_WALK) {
if (eToucher.classname == "player") {
Trigger(eToucher, TRIG_TOGGLE);
}
}
@ -406,6 +410,7 @@ func_button::PlayerUse(void)
if (HasSpawnFlags(SF_BTT_TOUCH_ONLY)) {
return;
}
Trigger(eActivator, TRIG_TOGGLE);
}
@ -415,4 +420,4 @@ func_button::Blocked(entity eBlocker)
if (m_flWait >= 0) {
MoveToReverse(m_flSpeed);
}
}
}

View File

@ -92,9 +92,9 @@ private:
float m_flDelay;
float m_flLip;
int m_iDamage;
int m_iLocked;
int m_iForceClosed;
bool m_iCanTouch;
bool m_bLocked;
bool m_bForceClosed;
bool m_bCanTouch;
float m_flSoundWait;
string m_strLockedSfx;
@ -115,14 +115,14 @@ func_door::func_door(void)
{
m_flLip =
m_flNextTrigger =
m_flWait =
m_flWait = -1; /* verified thorugh through test_door_locked.bsp */
m_flDelay = 0.0f;
m_iDamage =
m_iLocked =
m_iForceClosed = 0;
m_iDamage = 0i;
m_bLocked =
m_bForceClosed = false;
m_iCanTouch = false;
m_bCanTouch = false;
m_flSoundWait = 0.0f;
targetClose =
@ -150,8 +150,8 @@ func_door::Save(float handle)
SaveFloat(handle, "m_flSoundWait", m_flSoundWait);
SaveInt(handle, "m_iDamage", m_iDamage);
SaveInt(handle, "m_iLocked", m_iLocked);
SaveInt(handle, "m_iForceClosed", m_iForceClosed);
SaveBool(handle, "m_bLocked", m_bLocked);
SaveBool(handle, "m_bForceClosed", m_bForceClosed);
SaveString(handle, "m_strLockedSfx", m_strLockedSfx);
SaveString(handle, "m_strUnlockedSfx", m_strUnlockedSfx);
@ -187,11 +187,11 @@ func_door::Restore(string strKey, string strValue)
case "m_iDamage":
m_iDamage = ReadInt(strValue);
break;
case "m_iLocked":
m_iLocked = ReadInt(strValue);
case "m_bLocked":
m_bLocked = ReadBool(strValue);
break;
case "m_iForceClosed":
m_iForceClosed = ReadInt(strValue);
case "m_bForceClosed":
m_bForceClosed = ReadBool(strValue);
break;
case "m_strLockedSfx":
@ -234,23 +234,23 @@ func_door::SpawnKey(string strKey, string strValue)
switch (strKey) {
case "skin":
m_waterType = stoi(strValue);
m_waterType = ReadInt(strValue);
break;
case "speed":
m_flSpeed = stof(strValue);
m_flSpeed = ReadFloat(strValue);
break;
case "lip":
m_flLip = stof(strValue);
m_flLip = ReadFloat(strValue);
break;
case "wait":
m_flWait = stof(strValue);
m_flWait = ReadFloat(strValue);
break;
case "netname":
targetClose = strValue;
netname = __NULL__;
break;
case "dmg":
m_iDamage = stoi(strValue);
m_iDamage = ReadInt(strValue);
break;
case "snd_open":
m_strSndOpen = strValue;
@ -269,7 +269,7 @@ func_door::SpawnKey(string strKey, string strValue)
m_strSndMove = strValue;
break;
case "forceclosed":
m_iForceClosed = stoi(strValue);
m_bForceClosed = ReadInt(strValue);
break;
/* GoldSrc compat */
case "movesnd":
@ -282,10 +282,18 @@ func_door::SpawnKey(string strKey, string strValue)
break;
case "locked_sound":
x = stoi(strValue);
if (x == 0i)
break;
m_strLockedSfx = sprintf("func_button.hlsfx_%i", x+1i);
break;
case "unlocked_sound":
x = stoi(strValue);
if (x == 0i)
break;
m_strUnlockedSfx = sprintf("func_button.hlsfx_%i", x+1i);
break;
/* I/O */
@ -361,9 +369,9 @@ func_door::Respawn(void)
m_iValue = 0;
if (spawnflags & SF_MOV_USE)
m_iCanTouch = false;
m_bCanTouch = false;
else
m_iCanTouch = true;
m_bCanTouch = true;
if (HasSpawnFlags(SF_MOV_OPEN)) {
SetOrigin(m_vecPos2);
@ -376,8 +384,12 @@ func_door::Respawn(void)
_PortalClose();
}
if (targetname) {
m_iLocked = TRUE;
if (HasTargetname()) {
m_bCanTouch = false;
if (m_strLockedSfx != __NULL__) {
m_bLocked = true;
}
}
}
@ -405,7 +417,7 @@ func_door::PlayerUse(void)
if (!HasSpawnFlags(SF_MOV_USE))
return;
eActivator.flags &= ~FL_USE_RELEASED;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
Trigger(eActivator, TRIG_TOGGLE);
}
@ -416,23 +428,16 @@ func_door::MoverFinishesMoving(void)
MoveToPosition(GetMoverPosition1(), m_flSpeed);
}
if (targetClose && targetClose != "") {
/* when it starts open the positions are reversed... */
if (GetMoverState() == MOVER_POS1 ||
(HasSpawnFlags(SF_MOV_OPEN) && GetMoverState() == MOVER_POS2)) {
for (entity f = world; (f = find(f, ::targetname, targetClose));) {
NSEntity trigger = (NSEntity)f;
if (trigger.Trigger != __NULL__) {
trigger.Trigger(this, TRIG_TOGGLE);
}
}
}
}
/* we arrived at our starting position within the map */
if (GetMoverState() == MOVER_POS1) {
if (targetClose)
for (entity f = world; (f = find(f, ::targetname, targetClose));) {
NSEntity trigger = (NSEntity)f;
if (trigger.Trigger != __NULL__) {
trigger.Trigger(this, TRIG_TOGGLE);
}
}
if (m_strSndStop) {
StartSoundDef(m_strSndStop, CHAN_VOICE, true);
} else {
@ -494,8 +499,19 @@ func_door::MoverStartsMoving(void)
void
func_door::Trigger(entity act, triggermode_t triggerstate)
{
if (GetMaster(act) == 0)
/* Note: func_door, unlike func_door_rotating, does not respect locked here!
This inconsistency is in the original Half-Life as well! */
if (!GetMaster(act)) {
return;
}
if (m_flWait == -1 && GetMoverState() == MOVER_POS2) {
return;
}
if ((GetMoverState() == MOVER_1TO2) || (GetMoverState() == MOVER_2TO1)) {
return;
}
if (m_flNextTrigger > time) {
if (HasSpawnFlags(SF_MOV_TOGGLE) == false) {
@ -521,17 +537,25 @@ func_door::Trigger(entity act, triggermode_t triggerstate)
void
func_door::Touch(entity eToucher)
{
if (m_iCanTouch == false)
/* locked sound plays only when touched. still need another check in Trigger()
to see if it's locked in case it gets trigger targeted */
if (m_bLocked || !GetMaster(eToucher)) {
/* only bother playing the locked sound when the door is closed. */
if (GetMoverState() == MOVER_POS1) {
if (m_flSoundWait < time) {
StartSoundDef(m_strLockedSfx, CHAN_VOICE, true);
}
m_flSoundWait = time + 0.3f;
}
return;
}
if (HasSpawnFlags(SF_MOV_USE) == true)
if (m_bCanTouch == false) {
return;
}
if (m_iLocked || !GetMaster(eToucher)) {
if (m_flSoundWait < time)
Sound_Play(this, CHAN_VOICE, m_strLockedSfx);
m_flSoundWait = time + 0.3f;
if (HasSpawnFlags(SF_MOV_USE) == true) {
return;
}
@ -540,6 +564,7 @@ func_door::Touch(entity eToucher)
}
if (eToucher.movetype == MOVETYPE_WALK) {
/* only trigger if we're not above the door. */
if (eToucher.absmin[2] <= maxs[2] - 2) {
Trigger(eToucher, TRIG_TOGGLE);
}
@ -553,7 +578,7 @@ func_door::Blocked(entity eBlocker)
Damage_Apply(eBlocker, this, m_iDamage, 0, DMG_CRUSH);
}
if (!m_iForceClosed)
if (!m_bForceClosed)
if (m_flWait >= 0) {
MoveToReverse(m_flSpeed);
}

View File

@ -104,7 +104,7 @@ private:
float m_flWait;
float m_flDelay;
int m_iDamage;
int m_iLocked;
bool m_bLocked;
bool m_bCanTouch;
vector m_vecTurnDir;
};
@ -119,11 +119,11 @@ func_door_rotating::func_door_rotating(void)
m_strLockedSfx = __NULL__;
m_flSoundWait = 0.0f;
m_iDamage = 0i;
m_iLocked = 0i;
m_flDistance = 90.0f;
m_bLocked = false;
m_flDistance = 0.0f;
m_flSpeed = 100.0f;
m_flNextAction = 0.0f;
m_flWait = 0.0f;
m_flWait = -1;
m_flDelay = 4.0f;
m_bCanTouch = false;
m_vecTurnDir = g_vec_null;
@ -145,7 +145,7 @@ func_door_rotating::Save(float handle)
SaveFloat(handle, "m_flWait", m_flWait);
SaveFloat(handle, "m_flDelay", m_flDelay);
SaveInt(handle, "m_iDamage", m_iDamage);
SaveInt(handle, "m_iLocked", m_iLocked);
SaveBool(handle, "m_bLocked", m_bLocked);
SaveBool(handle, "m_bCanTouch", m_bCanTouch);
SaveVector(handle, "m_vecTurnDir", m_vecTurnDir);
}
@ -190,11 +190,11 @@ func_door_rotating::Restore(string strKey, string strValue)
case "m_iDamage":
m_iDamage = ReadInt(strValue);
break;
case "m_iLocked":
m_iLocked = ReadInt(strValue);
case "m_bLocked":
m_bLocked = ReadBool(strValue);
break;
case "m_bCanTouch":
m_bCanTouch = ReadInt(strValue);
m_bCanTouch = ReadBool(strValue);
break;
case "m_vecTurnDir":
m_vecTurnDir = ReadVector(strValue);
@ -280,8 +280,12 @@ func_door_rotating::Respawn(void)
SetSolid(SOLID_NOT);
}
if (targetname) {
m_iLocked = TRUE;
if (HasTargetname() || m_flDistance == 0.0) {
if (m_flDistance == 0.0 || m_strLockedSfx != __NULL__) {
m_bLocked = true;
} else {
m_bLocked = false;
}
}
SetAngles(GetMoverRotation1());
@ -331,6 +335,10 @@ func_door_rotating::SpawnKey(string strKey, string strValue)
break;
case "locked_sound":
x = stoi(strValue); /* sanitize */
if (x == 0i)
break;
m_strLockedSfx = sprintf("func_button.hlsfx_%i", x+1i);
break;
default:
@ -347,7 +355,7 @@ func_door_rotating::Unhinge(void)
m_bCanTouch = false;
SetSolid(SOLID_PHYSICS_BOX);
SetMovetype(MOVETYPE_PHYSICS);
physics_enable(this, TRUE);
physics_enable(this, true);
}
#endif
@ -411,11 +419,20 @@ func_door_rotating::MoverStartsMoving(void)
void
func_door_rotating::Trigger(entity act, triggermode_t state)
{
if (GetMaster(act) == FALSE) {
/* Note: Unlike func_door, this does respect the locked state in Trigger() */
if (m_bLocked || !GetMaster(act)) {
return;
}
eActivator = act;
if (m_flWait == -1 && GetMoverState() == MOVER_POS2) {
return;
}
if ((GetMoverState() == MOVER_1TO2) || (GetMoverState() == MOVER_2TO1)) {
return;
}
eActivator = (NSEntity)act;
/* this door can swing both ways */
if (!HasSpawnFlags(SF_ROT_ONEWAY)) {
@ -454,33 +471,35 @@ func_door_rotating::Trigger(entity act, triggermode_t state)
void
func_door_rotating::Use(void)
{
eActivator.flags &= ~FL_USE_RELEASED;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
Trigger(eActivator, TRIG_TOGGLE);
}
void
func_door_rotating::Touch(entity eToucher)
{
/* locked sound plays only when touched. still need another check in Trigger()
to see if it's locked in case it gets trigger targeted */
if (m_bLocked || !GetMaster(eToucher)) {
/* only bother playing the locked sound when the door is closed. */
if (GetMoverState() == MOVER_POS1) {
if (m_flSoundWait < time) {
StartSoundDef(m_strLockedSfx, CHAN_VOICE, true);
}
m_flSoundWait = time + 0.3f;
}
return;
}
if (m_bCanTouch == false) {
return;
}
if (m_iLocked || !GetMaster(eToucher)) {
if (m_flSoundWait < time)
Sound_Play(this, CHAN_VOICE, m_strLockedSfx);
m_flSoundWait = time + 0.3f;
return;
}
if (HasSpawnFlags(SF_ROT_USE)) {
return;
}
if ((GetMoverState() == MOVER_1TO2) || (GetMoverState() == MOVER_2TO1)) {
return;
}
if (eToucher.movetype == MOVETYPE_WALK) {
Trigger(eToucher, TRIG_TOGGLE);
}

View File

@ -47,7 +47,7 @@ public:
nonvirtual void ResetHealth(void);
private:
entity m_eUser;
NSEntity m_eUser;
float m_flDelay;
float m_flCheck;
@ -83,7 +83,7 @@ func_healthcharger::Restore(string strKey, string strValue)
{
switch (strKey) {
case "user":
m_eUser = ReadEntity(strValue);
m_eUser = (NSEntity)ReadEntity(strValue);
break;
case "delay":
m_flDelay = ReadFloat(strValue);
@ -162,14 +162,14 @@ func_healthcharger::OnPlayerUse(void)
if (eActivator.health <= 0)
return;
eActivator.flags |= FL_USE_RELEASED;
eActivator.AddVFlags(VFL_USE_RELEASED);
/* First come first serve */
if (m_eUser && eActivator != m_eUser)
return;
/* First time */
if (m_eUser == world) {
if (m_eUser == __NULL__) {
StartSound(m_strSndFirst, CHAN_VOICE, 0, true);
}
@ -177,17 +177,17 @@ func_healthcharger::OnPlayerUse(void)
return;
if (health <= 0) {
eActivator.flags &= ~FL_USE_RELEASED;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
StartSound(m_strSndDone, CHAN_VOICE, 0, true);
m_eUser = world;
m_eUser = __NULL__;
return;
}
if (eActivator.health >= 100) {
eActivator.flags &= ~FL_USE_RELEASED;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
StartSound(m_strSndDone, CHAN_VOICE, 0, true);
} else {
if (m_eUser == world) {
if (m_eUser == __NULL__) {
StartSound(m_strSndCharging, CHAN_ITEM, 0, true);
}
@ -204,8 +204,8 @@ func_healthcharger::OnPlayerUse(void)
StopSound(CHAN_ITEM, true);
StartSound(m_strSndDone, CHAN_VOICE, 0, true);
SetFrame(1);
eActivator.flags &= ~FL_USE_RELEASED;
m_eUser = world;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
m_eUser = __NULL__;
return;
}
}
@ -223,7 +223,7 @@ func_healthcharger::customphysics(void)
if (m_eUser) {
StopSound(CHAN_ITEM, true);
m_eUser = world;
m_eUser = __NULL__;
}
HandleThink();

View File

@ -168,7 +168,7 @@ func_recharge::OnPlayerUse(void)
return;
}
eActivator.flags |= FL_USE_RELEASED;
eActivator.AddVFlags(VFL_USE_RELEASED);
/* First come first serve */
if (m_eUser && eActivator != m_eUser) {
@ -185,7 +185,7 @@ func_recharge::OnPlayerUse(void)
}
if (health <= 0) {
eActivator.flags &= ~FL_USE_RELEASED;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
StartSound(m_strSndDone, CHAN_VOICE, 0, true);
m_eUser = world;
return;
@ -193,7 +193,7 @@ func_recharge::OnPlayerUse(void)
NSClientPlayer pl = (NSClientPlayer)eActivator;
if (pl.armor >= 100) {
eActivator.flags &= ~FL_USE_RELEASED;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
StartSound(m_strSndDone, CHAN_VOICE, 0, true);
} else {
if (m_eUser == world) {
@ -213,7 +213,7 @@ func_recharge::OnPlayerUse(void)
StopSound(CHAN_ITEM, true);
StartSound(m_strSndDone, CHAN_VOICE, 0, true);
SetFrame(1);
eActivator.flags &= ~FL_USE_RELEASED;
eActivator.RemoveVFlags(VFL_USE_RELEASED);
m_eUser = world;
return;
}

View File

@ -42,15 +42,15 @@ A button that rotates along a pivot point. Used for valves, spigots and alike.
# KEYS
- "targetname" : Name
- "target" : Name of the entity to trigger when opened
- "speed" : How fast the button rotates when activated.
- "speed" : How fast the button turns when activated.
- "health" : If non-zero, the button must be damaged to turn.
- "wait" : Time to wait before button resets itself. -1 makes it stay set.
- "wait" : Time until the button turns back. A value of -1 makes it stay static.
- "distance" : Distance in degrees the button will rotate.
# SPAWNFLAGS
- NONSOLID (1) : Don't do collision testing against this entity.
- REVERSE (2) : Rotate the counter-clockwise.
- NOAUTORETURN (32) : Will not return by itself.
- NONSOLID (1) : Button won't have collision.
- REVERSE (2) : Rotates counter-clockwise.
- NOAUTORETURN (32) : Will not return by itself.
- XAXIS (64) : Rotate along the X-axis.
- YAXIS (128) : Rotate along the Y-axis.
@ -247,7 +247,7 @@ func_rot_button::OnPlayerUse(void)
void
func_rot_button::Touch(entity eToucher)
{
eActivator = eToucher;
eActivator = (NSEntity)eToucher;
if (HasSpawnFlags(FNCROTBUT_TOUCHABLE))
TurnToggle();

View File

@ -191,9 +191,7 @@ func_tracktrain::GetPointBetweenNodes(float percentageValue)
vector newPos = g_vec_null;
path_track nextNode = GetTrackNodeForward();
path_track prevNode = GetTrackNodeBack();
newPos[0] = Math_Lerp(prevNode.origin[0], nextNode.origin[0], percentageValue);
newPos[1] = Math_Lerp(prevNode.origin[1], nextNode.origin[1], percentageValue);
newPos[2] = Math_Lerp(prevNode.origin[2], nextNode.origin[2], percentageValue);
newPos = vectorLerp(prevNode.origin, nextNode.origin, percentageValue);
return newPos;
}
@ -658,7 +656,7 @@ func_tracktrain::PathMoveForward(void)
/* the direction we're aiming for */
vecDiff = GetOrigin() - (eNode.GetOrigin() + [0, 0, m_flHeight]);
vecAngleDest = vectoangles(vecDiff);
vecAngleDiff = Math_AngleDiff(vecAngleDest, angles);
vecAngleDiff = angleDifference(vecAngleDest, angles);
vecAngleDiff[2] = 0;
if (vecAngleDiff[0] > 180)
@ -743,8 +741,8 @@ func_tracktrain::PathMoveBack(void)
/* the direction we're aiming for */
vecDiff = (eNode.GetOrigin() + [0, 0, m_flHeight]) - GetOrigin();
vecAngleDest = vectoangles(vecDiff);
vecAngleDiff = Math_AngleDiff(vecAngleDest, angles);
vecAngleDest = vectorToAngles(vecDiff);
vecAngleDiff = angleDifference(vecAngleDest, angles);
vecAngleDiff[2] = 0;
if (vecAngleDiff[0] > 180)
@ -980,7 +978,7 @@ func_tracktrain::_AfterSpawn(void)
if (IgnoresPitch() == true) {
newAngle[0] = 0;
} else {
newAngle[0] = -Math_FixDelta(newAngle[0]);
newAngle[0] = -fixAngleDelta(newAngle[0]);
}
SetAngles(newAngle);
@ -1074,9 +1072,7 @@ func_tracktrain::OnPlayerUse(void)
void
func_tracktrain::EvaluateEntity(void)
{
angles[0] = Math_FixDelta(angles[0]);
angles[1] = Math_FixDelta(angles[1]);
angles[2] = Math_FixDelta(angles[2]);
angles = fixAngle(angles);
PlayerAlign();
EVALUATE_FIELD(modelindex, FNCTKTRNET_MODELINDEX)

View File

@ -65,8 +65,8 @@ monster_generic::Respawn(void)
SetSize(base_mins, base_maxs);
if (HasSpawnFlags(MGF_NONSOLID)) {
takedamage = DAMAGE_NO;
MakeInvulnerable();
DisableBleeding();
SetSolid(SOLID_NOT);
SetCanBleed(false);
}
}

View File

@ -263,9 +263,9 @@ point_trigger::WillThisTrigger(entity eAct)
return true;
if (HasSpawnFlags(PTRIG_ALLIES) && eAct.flags & FL_MONSTER && eAct.m_iAlliance == MAL_FRIEND)
return true;
if (HasSpawnFlags(PTRIG_VEHPLAYER) && eAct.flags & FL_CLIENT && eAct.flags & FL_INVEHICLE)
if (HasSpawnFlags(PTRIG_VEHPLAYER) && eAct.flags & FL_CLIENT && eAct.vv_flags & VFL_INVEHICLE)
return true;
if (HasSpawnFlags(PTRIG_NOVEHCL) && eAct.flags & FL_CLIENT && !(eAct.flags & FL_INVEHICLE))
if (HasSpawnFlags(PTRIG_NOVEHCL) && eAct.flags & FL_CLIENT && !(eAct.vv_flags & VFL_INVEHICLE))
return true;
return false;

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*!QUAKED script_brushmodel (0 .5 .8) ? DYNAMICPATH
# OVERVIEW
Scripted Brush Model
# KEYS
- "targetname" : Name
# TRIVIA
This entity was introduced in Call of Duty (2003).
*/
class
script_brushmodel:NSBrushTrigger
{
public:
void script_brushmodel(void);
virtual void Trigger(entity, triggermode_t);
};
void
script_brushmodel::script_brushmodel(void)
{
}
void
script_brushmodel::Trigger(entity entityActivator, triggermode_t state)
{
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*!QUAKED script_model (1 0 0) (-16 -16 -16) (16 16 16) ORIENT_LOD NO_SHADOW NO_STATIC_SHADOWS
# OVERVIEW
Upon being triggered, the entity will spawn item_food in its place in
the shape of a soda can.
# KEYS
- "targetname" : Name
- "model" : Path of the model.
# SPAWNFLAGS
- ORIENT_LOD (1) : Turn to player when lod models change
- NO_SHADOW (2) : Will cast no shadows.
- NO_STATIC_SHADOWS (4) : Will cast no lightmap shadows.
# TRIVIA
This entity was introduced in Call of Duty (2003).
*/
class
script_model:NSPointTrigger
{
public:
void script_model(void);
virtual void Trigger(entity, triggermode_t);
};
void
script_model::script_model(void)
{
}
void
script_model::Trigger(entity entityActivator, triggermode_t state)
{
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*!QUAKED script_origin (1 0 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
A position hint entity, designed to be used by MapC.
# KEYS
- "targetname" : Name
# TRIVIA
This entity was introduced in Call of Duty (2003).
*/
class
script_origin:NSBrushTrigger
{
public:
void script_origin(void);
virtual void Trigger(entity, triggermode_t);
};
void
script_origin::script_origin(void)
{
}
void
script_origin::Trigger(entity entityActivator, triggermode_t state)
{
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*!QUAKED script_struct (1 0 0) (-8 -8 -8) (8 8 8)
# OVERVIEW
Unknown.
# KEYS
- "targetname" : Name
# TRIVIA
This entity was introduced in Call of Duty 2 (2005).
*/
class
script_struct:NSBrushTrigger
{
public:
void script_struct(void);
virtual void Trigger(entity, triggermode_t);
};
void
script_struct::script_struct(void)
{
}
void
script_struct::Trigger(entity entityActivator, triggermode_t state)
{
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*!QUAKED script_vehicle (1 0 0) (-16 -16 -16) (16 16 16) USABLE
# OVERVIEW
Unknown.
# KEYS
- "targetname" : Name
- "model" : Model to use for the vehicle.
- "vehicletype" : Name of the vehicle type.
# TRIVIA
This entity was introduced in Call of Duty (2003).
*/
class
script_vehicle:NSRenderableEntity
{
public:
void script_vehicle(void);
virtual void Trigger(entity, triggermode_t);
};
void
script_vehicle::script_vehicle(void)
{
}
void
script_vehicle::Trigger(entity entityActivator, triggermode_t state)
{
}

View File

@ -233,11 +233,11 @@ trigger_hurt::Touch(entity eToucher)
} else {
if (HasSpawnFlags(SF_HURT_FIREONPLAYER)) {
if (eToucher.flags & FL_CLIENT) {
eActivator = eToucher;
eActivator = (NSEntity)eToucher;
UseTargets(eToucher, TRIG_TOGGLE, m_flDelay);
}
} else {
eActivator = eToucher;
eActivator = (NSEntity)eToucher;
UseTargets(eToucher, TRIG_TOGGLE, m_flDelay);
}
}

View File

@ -139,7 +139,7 @@ trigger_multiple::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "wait":
m_flWait = stof(strValue);
m_flWait = ReadFloat(strValue);
break;
case "StartDisabled":
m_bStartDisabled = ReadBool(strValue);
@ -201,7 +201,10 @@ trigger_multiple::Input(entity entityActivator, string inputName, string dataFie
void
trigger_multiple::Touch(entity eToucher)
{
if (GetMaster(eToucher) == FALSE)
if (IsThinking() == true)
return;
if (GetMaster(eToucher) == false)
return;
if (m_bEnabled == false)

View File

@ -66,7 +66,7 @@ trigger_playerfreeze::Trigger(entity act, triggermode_t state)
/* force unfreeze */
for (entity f = world; (f = find(f, ::classname, "player"));) {
f.flags &= ~FL_FROZEN;
f.vv_flags &= ~VFL_FROZEN;
}
} else {
dprint("^2trigger_playerfreeze::^3Trigger^7: " \
@ -82,6 +82,6 @@ trigger_playerfreeze::customphysics(void)
/* some games might unset this flag every single frame */
for (entity f = world; (f = find(f, ::classname, "player"));) {
f.flags |= FL_FROZEN;
f.vv_flags |= VFL_FROZEN;
}
}

View File

@ -207,7 +207,7 @@ trigger_teleport::Touch(entity eToucher)
return;
if (eToucher.movetype != MOVETYPE_NONE) {
eActivator = eToucher;
eActivator = (NSEntity)eToucher;
entity eTarget = find(world, ::targetname, target);
if (eTarget) {
@ -242,15 +242,15 @@ trigger_teleport::Touch(entity eToucher)
setorigin_safe(eToucher, endpos);
if (m_sndTeleport) {
Sound_Play(eToucher, CHAN_VOICE, m_sndTeleport);
StartSoundDef(m_sndTeleport, CHAN_VOICE, true);
}
if (m_sndTeleportEnter) {
Sound_Play(this, CHAN_VOICE, m_sndTeleportEnter);
StartSoundDef(m_sndTeleportEnter, CHAN_VOICE, true);
}
if (m_sndTeleportExit) {
Sound_Play(eTarget, CHAN_VOICE, m_sndTeleportExit);
StartSoundDef(m_sndTeleportExit, CHAN_VOICE, true);
}
EntLog("Teleported %S to %v", eToucher.netname, endpos);

View File

@ -288,7 +288,8 @@ ambient_generic::UseNormal(entity act, triggermode_t state)
SndEntLog("Sample: %S Volume: %f; Radius: %d; Pitch: %f", m_strActivePath, m_flVolume, m_flRadius, m_flPitch);
if (substring(m_strActivePath, 0, 1) == "!") {
string seq = Sentences_GetSamples(m_strActivePath);
string sentenceWord = strtoupper(m_strActivePath);
string seq = Sentences_GetSamples(sentenceWord);
if (seq == "")
return;
@ -296,7 +297,7 @@ ambient_generic::UseNormal(entity act, triggermode_t state)
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_SENTENCE);
WriteEntity(MSG_MULTICAST, this);
WriteInt(MSG_MULTICAST, Sentences_GetID(m_strActivePath));
WriteInt(MSG_MULTICAST, Sentences_GetID(sentenceWord));
msg_entity = this;
multicast(origin, MULTICAST_PHS);
} else {

View File

@ -475,9 +475,7 @@ env_beam::predraw(void)
point = center + p;
} else {
point[0] = Math_Lerp(m_vecStartPos[0], m_vecEndPos[0], progression);
point[1] = Math_Lerp(m_vecStartPos[1], m_vecEndPos[1], progression);
point[2] = Math_Lerp(m_vecStartPos[2], m_vecEndPos[2], progression);
point = vectorLerp(m_vecStartPos, m_vecEndPos, progression);
}
/* get the direction the beam is 'looking' */

View File

@ -168,11 +168,9 @@ env_fog_controller::FogRender(void)
m_flNextDraw = cltime + 1.0f;
/* apply the fog. wish there was a builtin for this instead... */
localcmd(sprintf("set r_fog_linear 1; fog %f %f %f %f %f %f\n", \
localcmd(sprintf("set r_fog_linear 1; fog %f %v %f %f\n", \
m_flFogEnd,
Math_Lerp(m_vecFogColor[0], m_vecFogColor2[0], delta),
Math_Lerp(m_vecFogColor[1], m_vecFogColor2[1], delta),
Math_Lerp(m_vecFogColor[2], m_vecFogColor2[2], delta),
vectorLerp(m_vecFogColor, m_vecFogColor2, delta),
m_flFogMaxDensity,
m_flFogStart));

View File

@ -393,10 +393,7 @@ env_funnel::predraw(void)
endPos[2] += rand3 * 512.0f;
finalPos[0] = Math_Lerp(startPos[0], endPos[0], progress);
finalPos[1] = Math_Lerp(startPos[1], endPos[1], progress);
finalPos[2] = Math_Lerp(startPos[2], endPos[2], progress);
finalPos = vectorLerp(startPos, endPos, progress);
RenderGlow(finalPos, [64, 64], m_flProgression);
}

View File

@ -348,8 +348,8 @@ env_instructor_hint::postdraw(void)
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]);
hintPos[0] = lerp(32.0f, video_res[0] - sideOffset, positionValues[1]);
hintPos[1] = lerp(32.0f, video_res[1] - 32.0f, positionValues[2]);
}
/* draw the thing */

View File

@ -356,9 +356,7 @@ env_laser::predraw(void)
float a = 1.0f;
/* our steps from a - b */
point[0] = Math_Lerp(origin[0], m_vecEndPos[0], progression);
point[1] = Math_Lerp(origin[1], m_vecEndPos[1], progression);
point[2] = Math_Lerp(origin[2], m_vecEndPos[2], progression);
point = vectorLerp(origin, m_vecEndPos, progression);
/* get the direction the laser is 'looking' */
makevectors(vectoangles(m_vecEndPos - origin));

View File

@ -161,10 +161,7 @@ env_projectedtexture::EvaluateEntity(void)
SetSendFlags(PRTEXFL_CHANGED_ORIGIN);
}
if (ATTR_CHANGED(angles)) {
angles[0] = Math_FixDelta(angles[0]);
angles[1] = Math_FixDelta(angles[1]);
angles[2] = Math_FixDelta(angles[2]);
angles = fixAngle(angles);
SetSendFlags(PRTEXFL_CHANGED_ANGLES);
}
SAVE_STATE(origin)

View File

@ -55,7 +55,7 @@ A sprite entity manager with fancy overrides.
- ENVS_PLAYONCE (2) : Play once from start to finish, then make invisible.
# NOTES
Only used with an external sprite format, like SPR, SPRHL and SPR32.
Only used with an external sprite format, like SPR, SPRHL and SPR32, unless the material key is specified.
# TRIVIA
This entity was introduced in Half-Life (1998).

View File

@ -61,31 +61,36 @@ float
env_steam_particle::predraw(void)
{
float partSize;
float lerp = (lifetime / m_flLifeTime);
float alpha = m_flAlpha * lerp;
float lerpPos = (lifetime / m_flLifeTime);
float alpha = m_flAlpha * lerpPos;
vector color;
vector spriteRight;
vector spriteUp;
if (m_bEmissive)
color = m_vecColor;
else
color = (getlight(origin) / 255);
partSize = Math_Lerp(m_flStartSize, m_flEndSize, lerp);
partSize = lerp(m_flStartSize, m_flEndSize, lerpPos);
makevectors(g_view.GetCameraAngle());
/* we really don't want to do this here, but people
will mostly pass image samples and thus won't do orientation on the GPU. */
spriteRight = anglesToRight(g_view.GetCameraAngle());
spriteUp = anglesToUp(g_view.GetCameraAngle());
if (m_bType)
R_BeginPolygon("textures/sfx/heatsteam", 0, 0);
else
R_BeginPolygon("textures/sfx/steam", 0, 0);
R_PolygonVertex(origin + v_right * partSize - v_up * partSize, [1,1], m_vecColor, alpha);
R_PolygonVertex(origin - v_right * partSize - v_up * partSize, [0,1], m_vecColor, alpha);
R_PolygonVertex(origin - v_right * partSize + v_up * partSize, [0,0], m_vecColor, alpha);
R_PolygonVertex(origin + v_right * partSize + v_up * partSize, [1,0], m_vecColor, alpha);
R_PolygonVertex(origin + spriteRight * partSize - spriteUp * partSize, [1,1], m_vecColor, alpha);
R_PolygonVertex(origin - spriteRight * partSize - spriteUp * partSize, [0,1], m_vecColor, alpha);
R_PolygonVertex(origin - spriteRight * partSize + spriteUp * partSize, [0,0], m_vecColor, alpha);
R_PolygonVertex(origin + spriteRight * partSize + spriteUp * partSize, [1,0], m_vecColor, alpha);
R_EndPolygon();
if (lerp >= 1.0f) {
if (lerpPos >= 1.0f) {
remove(this);
}

View File

@ -169,7 +169,7 @@ func_tankmortar::ReceiveEntity(float new, float fChanged)
}
if (fChanged & VEHFL_CHANGED_DRIVER) {
m_eDriver = findfloat(world, ::entnum, readentitynum());
m_eDriver = (NSEntity)findfloat(world, ::entnum, readentitynum());
}
if (new)
@ -185,10 +185,7 @@ func_tankmortar::EvaluateEntity(void)
SetSendFlags(VEHFL_CHANGED_ORIGIN);
}
if (ATTR_CHANGED(angles)) {
angles[0] = Math_FixDelta(angles[0]);
angles[1] = Math_FixDelta(angles[1]);
angles[2] = Math_FixDelta(angles[2]);
angles = fixAngle(angles);
SetSendFlags(VEHFL_CHANGED_ANGLES);
}
if (ATTR_CHANGED(velocity)) {
@ -322,10 +319,8 @@ func_tankmortar::PlayerInput(void)
wantang = v_forward;
makevectors(angles);
endang[0] = Math_Lerp(v_forward[0], wantang[0], input_timelength);
endang[1] = Math_Lerp(v_forward[1], wantang[1], input_timelength);
endang[2] = Math_Lerp(v_forward[2], wantang[2], input_timelength);
angles = vectoangles(endang);
endang = vectorLerp(v_forward, wantang, input_timelength);
angles = vectorToAngles(endang);
PlayerUpdateFlags();
}

View File

@ -815,9 +815,7 @@ func_vehicle::RunVehiclePhysics(void)
m_eDriver.velocity = [0,0,0];
}
angles[0] = Math_FixDelta(angles[0]);
angles[1] = Math_FixDelta(angles[1]);
angles[2] = Math_FixDelta(angles[2]);
angles = fixAngle(angles);
angles[0] = bound (-45, angles[0], 45);
angles[2] = bound (-15, angles[2], 15);
@ -864,11 +862,7 @@ func_vehicle::RunVehiclePhysics(void)
v_forward = (m_wlFL.origin + m_wlFR.origin);
v_forward -= (m_wlBL.origin + m_wlBR.origin);
v_up = -crossproduct(v_forward, v_right);
angles = vectoangles(v_forward, v_up);
angles[0] = Math_FixDelta(angles[0]);
angles[1] = Math_FixDelta(angles[1]);
angles[2] = Math_FixDelta(angles[2]);
angles = vectorToAnglesRoll(v_forward, v_up);
/* figure out the new chassis position */
vector new_origin;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -139,9 +139,7 @@ phys_rope::predraw(void)
}
/* travel further and sag */
pos2[0] = Math_Lerp(origin[0], m_vecTarget[0], progress);
pos2[1] = Math_Lerp(origin[1], m_vecTarget[1], progress);
pos2[2] = Math_Lerp(origin[2], m_vecTarget[2], progress);
pos2 = vectorLerp(origin, m_vecTarget, progress);
pos2 += (v_up * -sag) * autocvar_rope_sag;
if (!autocvar_rope_fast)
@ -320,7 +318,7 @@ void
phys_rope::Restore(string strKey, string strValue)
{
switch (strKey) {
case "RopeMaterial":
case "m_strShader":
m_strShader = ReadString(strValue);
break;
case "m_flSag":
@ -329,7 +327,7 @@ phys_rope::Restore(string strKey, string strValue)
case "m_flSwingFactor":
m_flSwingFactor = ReadFloat(strValue);
break;
case "Subdiv":
case "m_iSegments":
m_iSegments = ReadInt(strValue);
break;
case "m_vecTarget":

View File

@ -154,9 +154,7 @@ prop_rope::predraw(void)
}
/* travel further and sag */
pos2[0] = Math_Lerp(origin[0], m_vecTarget[0], progress);
pos2[1] = Math_Lerp(origin[1], m_vecTarget[1], progress);
pos2[2] = Math_Lerp(origin[2], m_vecTarget[2], progress);
pos2 = vectorLerp(origin, m_vecTarget, progress);
pos2 += (v_up * -sag) * autocvar_rope_sag;
if (!autocvar_rope_fast)

View File

@ -15,7 +15,7 @@
*/
#define VEH_SKIDDING FL_USE_RELEASED
#define VEH_SKIDDING VFL_USE_RELEASED
#define VEHSF_NOFLIP 2048
@ -405,7 +405,7 @@ prop_vehicle_driveable_wheel::Accel(float flMoveTime, float m_flTurn)
/* test if this car is skidding */
float skid = (velocity * v_right);
if ( fabs(skid) > vehParent.m_flSkidSpeed ) {
vehParent.flags |= VEH_SKIDDING;
vehParent.vv_flags |= VEH_SKIDDING;
}
/* nuke sideways velocity. if a wheel is off the ground this probably
@ -632,11 +632,9 @@ prop_vehicle_driveable::RunVehiclePhysics(void)
angles[2] = bound (-45, angles[2], 45);
}
flags &= ~VEH_SKIDDING;
vv_flags &= ~VEH_SKIDDING;
angles[0] = Math_FixDelta(angles[0]);
angles[1] = Math_FixDelta(angles[1]);
angles[2] = Math_FixDelta(angles[2]);
angles = fixAngle(angles);
velocity[0] = bound(-1000, velocity[0], 1000);
velocity[1] = bound(-1000, velocity[1], 1000);
@ -821,10 +819,7 @@ prop_vehicle_driveable::EvaluateEntity(void)
SetSendFlags(VEHFL_ORIGIN);
if (ATTR_CHANGED(angles)) {
angles[0] = Math_FixDelta(angles[0]);
angles[1] = Math_FixDelta(angles[1]);
angles[2] = Math_FixDelta(angles[2]);
angles = fixAngle(angles);
SetSendFlags(VEHFL_ANGLES);
}
if (ATTR_CHANGED(modelindex))

View File

@ -308,8 +308,8 @@ trigger_camera::GoToTarget(void)
if (!m_strAimAt) {
vector vecAngleDiff = targetNode.GetOrigin() - GetOrigin();
vector vecAngleDest = vectoangles(vecAngleDiff);
vecAngleDiff = Math_AngleDiff(vecAngleDest, angles);
vector vecAngleDest = vectorToAngles(vecAngleDiff);
vecAngleDiff = angleDifference(vecAngleDest, angles);
SetAngularVelocity(vecAngleDiff * (1 / travelTime));
}

View File

@ -337,7 +337,7 @@ void
trigger_push::Touch(entity eToucher)
{
#ifdef SERVER
eActivator = eToucher;
eActivator = (NSEntity)eToucher;
#endif
switch(eToucher.movetype) {

View File

@ -39,6 +39,7 @@ Only used for the world.
- "hdr_iris_multiplier" : HDR effect multiplier. Default is "1.0".
- "hdr_iris_fade_up" : HDR iris fade up speed. Default is "0.1".
- "hdr_iris_fade_down" : HDR iris fade down speed. Default is "0.5".
- "_litwater" : Set to 1 for a HL BSP to have lightmapped water surfaces.
# NOTES
A map must only have one worldspawn entity.
@ -56,6 +57,8 @@ public:
void worldspawn(void);
virtual void Spawned(void);
virtual void Save(float);
virtual void Restore(string, string);
virtual void SpawnKey(string, string);
private:
@ -72,6 +75,7 @@ private:
float m_flHDRIrisFadeUp;
float m_flHDRIrisFadeDown;
bool m_bHDREnabled;
bool m_bLitWater;
};
void
@ -80,15 +84,19 @@ worldspawn::worldspawn(void)
/* defaults */
m_flHDRIrisMinValue = 0.0;
m_flHDRIrisMaxValue = 1.25;
m_flHDRIrisMultiplier = 1.25;
m_flHDRIrisFadeUp = 0.1;
m_flHDRIrisFadeDown = 0.2;
m_bHDREnabled = false;
m_bLitWater = false;
if (serverkeyfloat("*bspversion") == BSPVER_HL) {
m_strSkyName = "desert";
m_flHDRIrisMultiplier = 1.5;
m_flHDRIrisMaxValue = 1.5;
} else {
m_strSkyName = "";
m_flHDRIrisMultiplier = 0.75;
m_flHDRIrisMaxValue = 1.5;
}
m_bStartDark = false;
@ -115,10 +123,6 @@ worldspawn::worldspawn(void)
lightstyle(12, "mmnnmmnnnmmnn");
lightstyle(63, "a");
Skill_Init();
EntityDef_Init();
MapTweaks_Init();
precache_model("models/error.vvm");
if (autocvar_sv_levelexec)
@ -135,17 +139,36 @@ worldspawn::Spawned(void)
blocked = __NULL__;
forceinfokey(world, "skyname", m_strSkyName);
forceinfokey(world, "startdark", ftos(m_bStartDark));
forceinfokey(world, "chaptertitle", m_strChapterTitle);
forceinfokey(world, "ambientsound", m_strAmbientSound);
forceinfokey(world, "bgm", m_strBGMTrack);
forceinfokey(world, "gametitle", ftos(m_bGameTitle));
/* these set cvars so we kinda always want to set them to ~something~ */
forceinfokey(world, "hdr_iris_minvalue", ftos(m_flHDRIrisMinValue));
forceinfokey(world, "hdr_iris_maxvalue", ftos(m_flHDRIrisMaxValue));
forceinfokey(world, "hdr_iris_multiplier", ftos(m_flHDRIrisMultiplier));
forceinfokey(world, "hdr_iris_fade_up", ftos(m_flHDRIrisFadeUp));
forceinfokey(world, "hdr_iris_fade_down", ftos(m_flHDRIrisFadeDown));
forceinfokey(world, "hdr", ftos(m_bHDREnabled));
/* don't want to litter serverinfo with '0' keys. */
if (m_bGameTitle) {
forceinfokey(world, "gametitle", ftos(m_bGameTitle));
} else {
forceinfokey(world, "gametitle", "");
}
if (m_bStartDark) {
forceinfokey(world, "startdark", ftos(m_bStartDark));
} else {
forceinfokey(world, "startdark", "");
}
if (m_bLitWater) {
forceinfokey(world, "litwater", ftos(m_bLitWater));
} else {
forceinfokey(world, "litwater", "");
}
}
void
@ -196,11 +219,83 @@ worldspawn::SpawnKey(string strKey, string strValue)
case "MaxRange":
case "sounds":
break;
case "_litwater":
m_bLitWater = ReadBool(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
break;
}
}
void
worldspawn::Save(float handle)
{
super::Save(handle);
SaveString(handle, "m_strSkyName", m_strSkyName);
SaveBool(handle, "m_bStartDark", m_bStartDark);
SaveBool(handle, "m_bGameTitle", m_bGameTitle);
SaveString(handle, "m_strChapterTitle", m_strChapterTitle);
SaveString(handle, "m_strAmbientSound", m_strAmbientSound);
SaveString(handle, "m_strBGMTrack", m_strBGMTrack);
SaveFloat(handle, "m_flHDRIrisMinValue", m_flHDRIrisMinValue);
SaveFloat(handle, "m_flHDRIrisMaxValue", m_flHDRIrisMaxValue);
SaveFloat(handle, "m_flHDRIrisMultiplier", m_flHDRIrisMultiplier);
SaveFloat(handle, "m_flHDRIrisFadeUp", m_flHDRIrisFadeUp);
SaveFloat(handle, "m_flHDRIrisFadeDown", m_flHDRIrisFadeDown);
SaveBool(handle, "m_bHDREnabled", m_bHDREnabled);
SaveBool(handle, "m_bLitWater", m_bLitWater);
}
void
worldspawn::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_strSkyName":
m_strSkyName = ReadString(strValue);
break;
case "m_bStartDark":
m_bStartDark = ReadBool(strValue);
break;
case "m_bGameTitle":
m_bGameTitle = ReadBool(strValue);
break;
case "m_strChapterTitle":
m_strChapterTitle = ReadString(strValue);
break;
case "m_strAmbientSound":
m_strAmbientSound = ReadString(strValue);
break;
case "m_strBGMTrack":
m_strBGMTrack = ReadString(strValue);
break;
case "m_flHDRIrisMinValue":
m_flHDRIrisMinValue = ReadFloat(strValue);
break;
case "m_flHDRIrisMaxValue":
m_flHDRIrisMaxValue = ReadFloat(strValue);
break;
case "m_flHDRIrisMultiplier":
m_flHDRIrisMultiplier = ReadFloat(strValue);
break;
case "m_flHDRIrisFadeUp":
m_flHDRIrisFadeUp = ReadFloat(strValue);
break;
case "m_flHDRIrisFadeDown":
m_flHDRIrisFadeDown = ReadFloat(strValue);
break;
case "m_bHDREnabled":
m_bHDREnabled = ReadBool(strValue);
break;
case "m_bLitWater":
m_bLitWater = ReadBool(strValue);
break;
default:
super::Restore(strKey, strValue);
break;
}
}
#endif
#ifdef CLIENT

View File

@ -1,7 +1,6 @@
#includelist
../shared/fteextensions.qc
../shared/math.h
../shared/math.qc
../shared/global.h
../shared/platform.h
../platform/defs.h

View File

@ -121,7 +121,7 @@ cz_cbSprayChanged(void)
void
cz_sldTopcolorChanged(float val)
{
vector x = hsv2rgb(val * 360, 100, 100);
vector x = hsvToRGB(val * 360, 100, 100);
float id = x[2] + (x[1] << 8) + (x[0] << 16);
cvar_set("topcolor", sprintf("0x%x", id));
localcmd(sprintf("seta _cl_topcolor %f\n", val));
@ -131,7 +131,7 @@ cz_sldTopcolorChanged(float val)
void
cz_sldBottomcolorChanged(float val)
{
vector x = hsv2rgb(val * 360, 100, 100);
vector x = hsvToRGB(val * 360, 100, 100);
float id = x[2] + (x[1] << 8) + (x[0] << 16);
cvar_set("bottomcolor", sprintf("0x%x", id));
localcmd(sprintf("seta _cl_bottomcolor %f\n", val));
@ -435,8 +435,8 @@ menu_customize_init(void)
cz_sldBottomcolor.SetCallback(cz_sldBottomcolorChanged);
Widget_Add(fn_customize, cz_sldBottomcolor);
g_vecTopcolor = hsv2rgb(cvar("_cl_topcolor") * 360, 100, 100) / 255;
g_vecBottomcolor = hsv2rgb(cvar("_cl_bottomcolor") * 360, 100, 100) / 255;
g_vecTopcolor = hsvToRGB(cvar("_cl_topcolor") * 360, 100, 100) / 255;
g_vecBottomcolor = hsvToRGB(cvar("_cl_bottomcolor") * 360, 100, 100) / 255;
}
}

View File

@ -55,10 +55,4 @@ Util_CmdToKey(string cmd)
}
return sBindTx;
}
float
lerp(float fA, float fB, float fPercent)
{
return (fA * (1 - fPercent)) + (fB * fPercent);
}
}

View File

@ -327,8 +327,8 @@ NSGameRules::DamageApply(entity t, entity c, float dmg, int w, damageType_t type
/* don't allow any damage */
if (PlayerCanAttack(tp) == false) {
g_dmg_eAttacker = c;
g_dmg_eTarget = t;
g_dmg_eAttacker = (NSEntity)c;
g_dmg_eTarget = (NSEntity)t;
g_dmg_iDamage = 0;
g_dmg_iHitBody = 0;
g_dmg_iFlags = type;
@ -359,8 +359,8 @@ NSGameRules::DamageApply(entity t, entity c, float dmg, int w, damageType_t type
eTarget.SetHealth(eTarget.GetHealth() - dmg);
/* the globals... */
g_dmg_eAttacker = c;
g_dmg_eTarget = t;
g_dmg_eAttacker = (NSEntity)c;
g_dmg_eTarget = (NSEntity)t;
g_dmg_iDamage = dmg;
g_dmg_iHitBody = trace_surface_id;
g_dmg_iFlags = type;
@ -519,7 +519,7 @@ NSGameRules::IntermissionEnd(void)
if (time < m_flIntermissionTime)
return;
if (!(input_buttons & INPUT_BUTTON0) && !(input_buttons & INPUT_BUTTON2))
if (!(input_buttons & INPUT_PRIMARY) && !(input_buttons & INPUT_JUMP))
return;
localcmd("nextmap\n");

65
src/server/cmd_cl.qc Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
bool
Cmd_ParseClientCommand(NSClient sender, string cmd, int commandArguments)
{
switch (argv(0)) {
case "say":
if (commandArguments == 2)
g_grMode.ChatMessageAll(sender, argv(1));
else
g_grMode.ChatMessageAll(sender, substring(cmd, 5, -2));
break;
case "say_team":
if (commandArguments == 2)
g_grMode.ChatMessageTeam(sender, argv(1));
else
g_grMode.ChatMessageTeam(sender, substring(cmd, 10, -2));
break;
case "spectate":
if (sender.classname != "player")
break;
player pl = (player)sender;
pl.MakeSpectator();
break;
case "play":
if (sender.classname != "spectator")
break;
spawnfunc_player();
PutClientInServer();
break;
case "setpos":
if (cvar("sv_cheats") == 1) {
setorigin(sender, stov(argv(1)));
}
break;
case "timeleft":
string msg;
string timestring;
float timeleft;
timeleft = cvar("timelimit") - (time / 60);
timestring = Util_TimeToString(timeleft);
msg = sprintf("we have %s minutes remaining", timestring);
bprint(PRINT_CHAT, msg);
break;
default:
clientcommand(sender, cmd);
}
}

248
src/server/cmd_sv.qc Normal file
View File

@ -0,0 +1,248 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
static void
CMD_TraceMaterial(void)
{
vector traceStart;
vector traceEnd;
string textureName;
traceStart = self.origin + self.view_ofs;
makevectors(self.v_angle);
traceEnd = traceStart + (v_forward * 4096);
traceline(traceStart, traceEnd, MOVE_HITMODEL, self);
trace_surface_id = getsurfacenearpoint(trace_ent, trace_endpos);
trace_surfacename = getsurfacetexture(trace_ent, trace_surface_id);
printf("trace_allsolid: %g\n", trace_allsolid);
printf("trace_startsolid: %g\n", trace_startsolid);
printf("trace_fraction: %f\n", trace_fraction);
printf("trace_endpos: %v\n", trace_endpos);
printf("trace_plane_normal: %v\n", trace_plane_normal);
printf("trace_plane_dist: %f\n", trace_plane_dist);
printf("trace_inopen: %g\n", trace_inopen);
printf("trace_inwater: %g\n", trace_inwater);
printf("trace_endcontents: %i\n", trace_endcontentsi);
printf("trace_surfaceflags: %i\n", trace_surfaceflagsi);
printf("trace_brush_id: %i\n", trace_brush_id);
printf("trace_brush_faceid: %i\n", trace_brush_faceid);
printf("trace_surface_id: %i\n", trace_surface_id);
printf("trace_bone_id: %i\n", trace_bone_id);
printf("trace_triangle_id: %i\n", trace_triangle_id);
printf("trace_surfacename: %S\n", trace_surfacename);
if (trace_surface_id == 0) {
printf("Unable to trace against a valid surface.\n");
return;
}
textureName = getsurfacetexture(trace_ent, trace_surface_id);
localcmd(sprintf("r_showshader %S\n", textureName));
}
static void
CMD_AddBot(void)
{
string botProfile = strtolower(argv(1));
float teamValue = stof(argv(2));
float spawnDelay = stof(argv(3));
string newName = argv(4);
Bot_AddBot_f(botProfile, teamValue, spawnDelay, newName);
}
static void
CMD_KillClass(void)
{
string targetClass;
targetClass = argv(1);
if (targetClass)
for (entity a = world; (a = find(a, ::classname, targetClass));) {
NSEntity t = (NSEntity)a;
t.Destroy();
}
}
static void
CMD_KillMovables(void)
{
for (entity a = world; (a = findfloat(a, ::movetype, MOVETYPE_PHYSICS));) {
NSEntity t = (NSEntity)a;
t.Destroy();
}
}
static void
CMD_Trigger(void)
{
string targ;
targ = argv(1);
if (targ)
for (entity a = world; (a = find(a, ::targetname, targ));) {
NSEntity t = (NSEntity)a;
if (t.Trigger)
t.Trigger(self, TRIG_TOGGLE);
}
}
static void
CMD_Input(void)
{
float entNum = stof(argv(1));
string inputName = argv(2);
string inputData = argv(3);
NSEntity inputTarget = (NSEntity)edict_num(entNum);
if (inputTarget) {
inputTarget.Input(self, inputName, inputData);
print(sprintf("Sending input to %d, %S: %S\n", entNum, inputName, inputData));
}
}
static void
CMD_ListTargets(void)
{
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
if (a.targetname) {
print(sprintf("%d: %s (%s)\n", num_for_edict(a), a.targetname, a.classname));
}
}
}
static void
CMD_Teleport(void)
{
static entity targetFinder;
targetFinder = find(targetFinder, ::targetname, argv(1));
/* try at least one more time to skip world */
if (!targetFinder)
targetFinder = find(targetFinder, ::targetname, argv(1));
if (targetFinder)
setorigin(self, targetFinder.origin);
}
static void
CMD_TeleportToClass(void)
{
static entity finder;
finder = find(finder, ::classname, argv(1));
/* try at least one more time to skip world */
if (!finder)
finder = find(finder, ::classname, argv(1));
if (finder)
setorigin(self, finder.origin);
}
static void
CMD_RenetworkEntities(void)
{
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
NSEntity ent = (NSEntity)a;
ent.SendFlags = -1;
}
}
static void
CMD_RespawnEntities(void)
{
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
NSEntity ent = (NSEntity)a;
ent.Respawn();
}
}
static void
CMD_Spawn(void)
{
NSEntity unit = EntityDef_CreateClassname(argv(1));
makevectors(self.v_angle);
traceline(self.origin, self.origin + (v_forward * 1024), MOVE_NORMAL, self);
setorigin(unit, trace_endpos);
}
bool
Cmd_ParseServerCommand(void)
{
switch (argv(0)) {
case "addBot":
CMD_AddBot();
break;
case "killAllBots":
Bot_KillAllBots();
break;
case "resetAllBotsGoals":
Bot_ResetAllBotsGoals();
break;
case "listBotProfiles":
Bot_ListBotProfiles_f();
break;
case "killClass":
CMD_KillClass();
break;
case "killMovables":
CMD_KillMovables();
break;
case "trigger":
CMD_Trigger();
break;
case "input":
CMD_Input();
break;
case "listTargets":
CMD_ListTargets();
break;
case "teleport":
CMD_Teleport();
break;
case "teleportToClass":
CMD_TeleportToClass();
break;
case "renetworkEntities":
CMD_RenetworkEntities();
break;
case "respawnEntities":
CMD_RespawnEntities();
break;
case "spawn":
CMD_Spawn();
break;
#ifdef BOT_INCLUDED
case "way":
Way_Cmd();
break;
#endif
case "listEntityDef":
EntityDef_DebugList();
break;
case "listSoundDef":
Sound_DebugList();
break;
case "traceMaterial":
CMD_TraceMaterial();
break;
default:
return (false);
}
return (true);
}

View File

@ -23,6 +23,8 @@
#include "weapons.h"
#include "plugins.h"
#include "NSTraceAttack.h"
#include "../shared/weapons.h"
#include "../shared/weapon_common.h"
#include "route.h"
#include "way.h"
@ -109,7 +111,7 @@ void Event_ServerModelEvent(float, int, string);
void Mapcycle_Load(string);
entity eActivator;
NSEntity eActivator;
/* Generic entity fields */
.void(void) PlayerUse;
@ -129,8 +131,8 @@ string startspot;
string __fullspawndata;
/* damage related tempglobals, like trace_* */
entity g_dmg_eAttacker;
entity g_dmg_eTarget;
NSEntity g_dmg_eAttacker;
NSEntity g_dmg_eTarget;
int g_dmg_iDamage;
int g_dmg_iRealDamage;
bodyType_t g_dmg_iHitBody;
@ -152,6 +154,42 @@ void main(void)
#define SAVE_STRING(x,y,z) fputs(x, sprintf("%S \"%s\" ", y, z))
#define SAVE_HEX(x,y,z) fputs(x, sprintf("%S \"%x\" ", y, z))
/** When called will turn the entity 'self' into the specified classname.
This is useful for entities that are already in the game, and need to transition into a different type of entity.
@param className is the type of class to be changed to. */
NSEntity EntityDef_SpawnClassname(string className);
/** Spawns an entity of a specific class. If class doesn't exist, returns __NULL__.
@param className is the type of class to be instantiated. */
NSEntity EntityDef_CreateClassname(string className);
/** Spawns an entity of a class, guaranteed to be valid.
This is the primary, encouraged method of spawning entities.
If you don't spawn an entity class using this, it will not respond to sendInput().
If a specified class does not exist, it will create an info_notnull type entity, but with the new, desired classname.
The only time when this function returns __NULL__ is if the game is unable to allocate any more entities.
@param className is the type of class to be instantiated. */
NSEntity Entity_CreateClass(string className);
/** Checks if an entity class was defined in an EntityDef.
You can then use EntityDef_GetKeyValue() to get various key values from said EntityDef.
@param className specifies which class definition to look for. */
bool EntityDef_HasSpawnClass(string className);
/** Retrieves the value of a specific key defined within an EntityDef.
@param className specifies which class definition to look in.
@param keyName specifies the 'key' we want to know its value of. */
string EntityDef_GetKeyValue(string className, string keyName);

View File

@ -166,6 +166,11 @@ EntityDef_ReadFile(string filePath)
/* increment the def count */
if (g_entDefCount < ENTITYDEF_MAX)
g_entDefCount++;
if (g_entDefCount >= ENTITYDEF_MAX) {
NSError("Reached limit of %d defs.", ENTITYDEF_MAX);
return;
}
}
currentDef.entClass = "";
currentDef.spawnClass = "";
@ -199,9 +204,6 @@ EntityDef_ReadFile(string filePath)
} else if (word == "inherit") {
currentDef.inheritKeys = argv(i+1);
i++;
} else if (substring(word, 0, 7) == "editor_") {
/* do nothing */
i++;
} else if (substring(word, 0, 4) == "when") {
switch (argv(i+2)) {
case "equals":
@ -248,6 +250,7 @@ EntityDef_ReadFile(string filePath)
void
EntityDef_Init(void)
{
string mapDef = sprintf("maps/%s.def", cvar_string("mapname"));
searchhandle pm;
InitStart();
@ -272,22 +275,10 @@ EntityDef_Init(void)
}
}
#if 0
for (int i = 0i; i < g_entDefCount; i++) {
int numKeys = tokenize_console(g_entDefTable[i].spawnData);
print(sprintf("edef %i: %S\n", i, g_entDefTable[i].entClass));
print(sprintf("\tspawnclass: %S\n", g_entDefTable[i].spawnClass));
print(sprintf("\tinheritKeys: %S\n", g_entDefTable[i].inheritKeys));
print(sprintf("\ttweakDefs %S\n", g_entDefTable[i].tweakDefs));
print(sprintf("\ttweakKeys %S\n", g_entDefTable[i].tweakKeys));
print(sprintf("\teventList %S\n", g_entDefTable[i].eventList));
print("\tspawnData:\n");
for (int c = 0; c < numKeys; c+=2) {
print(sprintf("\t\t%S %S\n", argv(c), argv(c+1)));
}
/* load the map specific def file */
if (FileExists(mapDef)) {
EntityDef_ReadFile(mapDef);
}
#endif
InitEnd();
}
@ -503,7 +494,10 @@ EntityDef_SpawnClassname(string className)
for (int i = 0i; i < g_entDefCount; i++) {
if (className == g_entDefTable[i].entClass) {
EntityDef_Precaches(i);
if (time < 1.0) {
EntityDef_Precaches(i);
}
NSLog("Spawning eDef %S", className);
return EntityDef_PrepareEntity(self, i);
}
@ -594,6 +588,7 @@ CallSpawnfuncByName(entity target, string className)
self = oldSelf;
}
NSEntity
Entity_CreateClass(string className)
{
@ -605,4 +600,23 @@ Entity_CreateClass(string className)
}
return newEntity;
}
}
void
EntityDef_DebugList(void)
{
for (int i = 0i; i < g_entDefCount; i++) {
int numKeys = tokenize_console(g_entDefTable[i].spawnData);
print(sprintf("edef %i: %S\n", i, g_entDefTable[i].entClass));
print(sprintf("\tspawnclass: %S\n", g_entDefTable[i].spawnClass));
print(sprintf("\tinheritKeys: %S\n", g_entDefTable[i].inheritKeys));
print(sprintf("\ttweakDefs %S\n", g_entDefTable[i].tweakDefs));
print(sprintf("\ttweakKeys %S\n", g_entDefTable[i].tweakKeys));
print(sprintf("\teventList %S\n", g_entDefTable[i].eventList));
print("\tspawnData:\n");
for (int c = 0; c < numKeys; c+=2) {
print(sprintf("\t\t%S %S\n", argv(c), argv(c+1)));
}
}
}

View File

@ -21,8 +21,6 @@ static int g_ent_spawned;
void
StartFrame(void)
{
PMove_StartFrame();
/* For entity parenting to work, we need to go through and run on every
* this method on every NSEntity class */
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
@ -180,7 +178,8 @@ PutClientInServer(void)
trigger_auto_trigger();
if (g_grMode.InIntermission() == true) {
g_grMode.IntermissionToPlayer((NSClientPlayer)self);
NSClientPlayer pl = (NSClientPlayer)self;
g_grMode.IntermissionToPlayer(pl);
}
}
@ -321,51 +320,9 @@ SV_ParseClientCommand(string cmd)
if (g_grMode.ClientCommand((NSClient)self, cmd) == true)
return;
argc = tokenize(cmd);
argc = (int)tokenize(cmd);
switch (argv(0)) {
case "say":
if (argc == 2)
g_grMode.ChatMessageAll((NSClient)self, argv(1));
else
g_grMode.ChatMessageAll((NSClient)self, substring(cmd, 5, -2));
break;
case "say_team":
if (argc == 2)
g_grMode.ChatMessageTeam((NSClient)self, argv(1));
else
g_grMode.ChatMessageTeam((NSClient)self, substring(cmd, 10, -2));
break;
case "spectate":
if (self.classname != "player")
break;
player pl = (player)self;
pl.MakeSpectator();
break;
case "play":
if (self.classname != "spectator")
break;
spawnfunc_player();
PutClientInServer();
break;
case "setpos":
if (cvar("sv_cheats") == 1) {
setorigin(self, stov(argv(1)));
}
break;
case "timeleft":
string msg;
string timestring;
float timeleft;
timeleft = cvar("timelimit") - (time / 60);
timestring = Util_TimeToString(timeleft);
msg = sprintf("we have %s minutes remaining", timestring);
bprint(PRINT_CHAT, msg);
break;
default:
clientcommand(self, cmd);
}
Cmd_ParseClientCommand((NSClient)self, cmd, argc);
}
/** Called when the QC module gets loaded.
@ -378,6 +335,10 @@ init(float prevprogs)
NSLog("Built: %s %s", __DATE__, __TIME__);
NSLog("QCC: %s", __QCCVER__);
Skill_Init();
EntityDef_Init();
MapTweaks_Init();
MapC_Init();
Plugin_Init();
Constants_Init();
@ -475,6 +436,7 @@ initents(void)
* let's add our own that we can actually trust. */
forceinfokey(world, "sv_playerslots", cvar_string("sv_playerslots"));
MapC_CallMainFunction();
Plugin_InitEnts();
Mapcycle_Init();
Vote_Init();
@ -535,121 +497,7 @@ ConsoleCmd(string cmd)
/* time to handle commands that apply to all games */
tokenize(cmd);
switch (argv(0)) {
case "addBot":
string botProfile = strtolower(argv(1));
float teamValue = stof(argv(2));
float spawnDelay = stof(argv(3));
string newName = argv(4);
Bot_AddBot_f(botProfile, teamValue, spawnDelay, newName);
break;
case "killAllBots":
Bot_KillAllBots();
break;
case "resetAllBotsGoals":
Bot_ResetAllBotsGoals();
break;
case "listBotProfiles":
Bot_ListBotProfiles_f();
break;
case "killClass":
string targetClass;
targetClass = argv(1);
if (targetClass)
for (entity a = world; (a = find(a, ::classname, targetClass));) {
NSEntity t = (NSEntity)a;
t.Destroy();
}
break;
case "killMovables":
for (entity a = world; (a = findfloat(a, ::movetype, MOVETYPE_PHYSICS));) {
NSEntity t = (NSEntity)a;
t.Destroy();
}
break;
case "trigger":
string targ;
targ = argv(1);
if (targ)
for (entity a = world; (a = find(a, ::targetname, targ));) {
NSEntity t = (NSEntity)a;
if (t.Trigger)
t.Trigger(self, TRIG_TOGGLE);
}
break;
case "input":
float entNum = stof(argv(1));
string inputName = argv(2);
string inputData = argv(3);
NSEntity inputTarget = (NSEntity)edict_num(entNum);
if (inputTarget) {
inputTarget.Input(self, inputName, inputData);
print(sprintf("Sending input to %d, %S: %S\n", entNum, inputName, inputData));
}
break;
case "listTargets":
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
if (a.targetname) {
print(sprintf("%d: %s (%s)\n", num_for_edict(a), a.targetname, a.classname));
}
}
break;
case "teleport":
static entity targetFinder;
targetFinder = find(targetFinder, ::targetname, argv(1));
/* try at least one more time to skip world */
if (!targetFinder)
targetFinder = find(targetFinder, ::targetname, argv(1));
if (targetFinder)
setorigin(pl, targetFinder.origin);
break;
case "teleportToClass":
static entity finder;
finder = find(finder, ::classname, argv(1));
/* try at least one more time to skip world */
if (!finder)
finder = find(finder, ::classname, argv(1));
if (finder)
setorigin(pl, finder.origin);
break;
case "renetworkEntities":
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
NSEntity ent = (NSEntity)a;
ent.SendFlags = -1;
}
break;
case "respawnEntities":
for (entity a = world; (a = findfloat(a, ::identity, 1));) {
NSEntity ent = (NSEntity)a;
ent.Respawn();
}
break;
case "spawn":
NSEntity unit = EntityDef_CreateClassname(argv(1));
makevectors(pl.v_angle);
traceline(pl.origin, pl.origin + (v_forward * 1024), MOVE_NORMAL, pl);
setorigin(unit, trace_endpos);
break;
#ifdef BOT_INCLUDED
case "way":
Way_Cmd();
break;
#endif
case "listSoundDef":
Sound_DebugList();
break;
default:
return (0);
}
return (1);
return Cmd_ParseServerCommand();
}
/** Returns TRUE if the server can pause the server when the 'pause' command

View File

@ -15,5 +15,8 @@ modelevent.qc
mapcycle.qc
entityDef.qc
maptweaks.qc
scripts.qc
cmd_cl.qc
cmd_sv.qc
entry.qc
#endlist

View File

@ -81,7 +81,7 @@ CheatersLament(NSClientPlayer playerEntity, vector absAngles, float buttons, flo
playerEntity.pb_player_delta = 0.0f;
/* if the player is firing, calculate the player delta */
if (buttons & INPUT_BUTTON0 || buttons & INPUT_BUTTON3) { /* primary & secondary fire counts */
if (buttons & INPUT_PRIMARY || buttons & INPUT_SECONDARY) { /* primary & secondary fire counts */
vector deltaPosition;
float deltaDegrees;

114
src/server/mapC.h Normal file
View File

@ -0,0 +1,114 @@
#pragma target fte_5768
#define QWSSQC
/* MapProgs are map specific QuakeC progs.
Include this file with YOUR MapProgs! */
#include "../shared/fteextensions.qc"
#include "../shared/global.h"
#include "../shared/math.h"
#include "../shared/math_vector.h"
#define entity_def(x, ...) const string x[] = { __VA_ARGS__ }
/** Calls a function (with parameters) in a new thread. */
#define thread(x) if (fork()) { x; abort(); }
/** Spawns an entity of a specific class.
This is the primary, encouraged method of spawning entities in MapC.
If you don't spawn an entity class using this, it will not respond to sendInput().
If a specified class does not exist, it will create an info_notnull type entity, but with the new, desired classname.
The only time when this function returns __NULL__ is if the server is unable to allocated any more entities.
@param className is the type of class to be instantiated.
@param desiredPos is the world position at which the new entity will be placed. */
entity
spawnClass(string className, vector desiredPos)
{
entity(string, vector) spawnFunc = externvalue(0, "MapC_CreateEntityClass");
return spawnFunc(className, desiredPos);
}
/** Sends an input (See NSIO::Input) to an entity.
While you're able to manipulate entities in most ways using bare MapC, you might want to change Nuclide specific attributes of them as well. This can only be done using the I/O system.
For the variety of inputs an entity supports, please look at the respective entity-specific documentation.
@param target is the entity which will receive the input
@param inputName is the name of the input. E.g. "SetOrigin"
@param dataString contains parameters for the input. E.g. "0 0 0"
@param activator references which entity is "responsible" for triggering this input. */
void
sendInput(entity target, string inputName, string dataString, entity activator)
{
void(entity, entity, string, string) inputFunc = externvalue(0, "MapC_SendEntityInput");
inputFunc(target, activator, inputName, setValue);
}
/** Does damage to all entities within a specified radius with a linear falloff.
@param position specifies the position at which the damage event occurs.
@param radius specifies the radius in game units.
@param maxDamage the maximum amount of damage this event can do.
@param minDamage the damage done to the entities on the outer-most rim of the radius.
@param attacker (optional) the source of the attack, defaults to world */
void
radiusDamage(vector position, float radius, int maxDamage, int minDamage, optional entity attacker)
{
void(vector, float, int, int, entity) damageFunc = externvalue(0, "MapC_RadiusDamage");
damageFunc(position, radius, maxDamage, minDamage, attacker);
}
/** Returns true/false depending on if the entity is an AI character.
@param entityToCheck specifies the entity to check.*/
bool
isAI(entity entityToCheck)
{
bool(entity) checkFunc = externvalue(0, "MapC_IsAI");
return checkFunc(entityToCheck);
}
/** Returns true/false depending on if the entity is alive.
@param entityToCheck specifies the entity to check.*/
bool
isAlive(entity entityToCheck)
{
bool(entity) checkFunc = externvalue(0, "MapC_IsAlive");
return checkFunc(entityToCheck);
}
/** Returns true/false depending on if the entity is in "god" mode.
@param entityToCheck specifies the entity to check.*/
bool
isGodMode(entity entityToCheck)
{
bool(entity) checkFunc = externvalue(0, "MapC_IsGodMode");
return checkFunc(entityToCheck);
}
/** Returns true/false depending on if the entity is a player.
@param entityToCheck specifies the entity to check.*/
bool
isPlayer(entity entityToCheck)
{
bool(entity) checkFunc = externvalue(0, "MapC_IsPlayer");
return checkFunc(entityToCheck);
}
/** Returns true/false depending on if the entity is either a player, or AI character.
@param entityToCheck specifies the entity to check.*/
bool
isSentient(entity entityToCheck)
{
bool(entity) checkFunc = externvalue(0, "MapC_IsSentient");
return checkFunc(entityToCheck);
}

View File

@ -248,11 +248,21 @@ Nodes_Init(void)
#define NODE_LINE_ALPHA 0.25f
/* draws debug graphics of our node tree */
var bool autocvar_r_renderEntityInfo = false;
void
SV_AddDebugPolygons(void)
{
Way_DrawDebugInfo();
if (autocvar_r_renderEntityInfo) {
makevectors(self.v_angle);
for (entity s = world; (s = findfloat(s, ::identity, 1));) {
NSEntity drawMe = (NSEntity)s;
drawMe.DebugDraw();
}
}
if (cvar("developer") != 1)
return;
@ -266,25 +276,5 @@ SV_AddDebugPolygons(void)
train.RenderDebugInfo();
}
#endif
makevectors(self.v_angle);
for (entity s = world; (s = findfloat(s, ::identity, 1));) {
NSEntity drawMe = (NSEntity)s;
drawMe.DebugDraw();
}
return;
/* draw the rectangles */
R_BeginPolygon("textures/dev/info_node", 0, 0);
for (int i = 0; i < g_iNodes; i++) {
node_t *w = g_pNodes + i;
R_PolygonVertex(w->origin + v_right * 8 - v_up * 8, [1,1], NODE_RECT_COLOR, NODE_RECT_ALPHA);
R_PolygonVertex(w->origin - v_right * 8 - v_up * 8, [0,1], NODE_RECT_COLOR, NODE_RECT_ALPHA);
R_PolygonVertex(w->origin - v_right * 8 + v_up * 8, [0,0], NODE_RECT_COLOR, NODE_RECT_ALPHA);
R_PolygonVertex(w->origin + v_right * 8 + v_up * 8, [1,0], NODE_RECT_COLOR, NODE_RECT_ALPHA);
R_EndPolygon();
}
}
#endif

157
src/server/scripts.qc Normal file
View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2024 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var float g_mapCProgs;
void
MapC_Init(void)
{
string mapProgs;
/* mapname global is not set yet in init() */
mapProgs = sprintf("maps/%s.dat", cvar_string("mapname"));
/* No mapname.dat, exit out */
if (FileExists(mapProgs) == false) {
NSError("MapC for level %s at %S does not exist.", mapname, mapProgs);
return;
}
NSLog("...adding MapC progs %S",mapProgs);
g_mapCProgs = addprogs(mapProgs);
}
void
MapC_CallMainFunction(void)
{
void(void) mainFunction;
mainFunction = externvalue(g_mapCProgs, "main");
if (mainFunction) {
externset(g_mapCProgs, world, "self");
mainFunction();
} else {
NSError("%s does not have a main function.", mapname);
}
}
void
MapC_CallNamedFunction(entity functionActivator, string targetFunction)
{
void(void) ourFunction;
ourFunction = externvalue(g_mapCProgs, targetFunction);
if (ourFunction) {
externset(g_mapCProgs, functionActivator, "self");
ourFunction();
} else {
NSError("%s does not have a function %s.", mapname, targetFunction);
}
}
/* Returns a new entity. Guaranteed to be something. Never __NULL__
unless we're seriously out of memory. */
entity
MapC_CreateEntityClass(string className, vector desiredPos)
{
NSEntity newEntity = Entity_CreateClass(className);
/* That class didn't exist, so let's take the base Nuclide one */
if (!newEntity) {
newEntity = Entity_CreateClass("NSEntity");
}
/* OOM. It's over. */
if (!newEntity) {
return __NULL__;
}
newEntity.classname = className;
newEntity.Input(newEntity, "SetSpawnOrigin", vtos(desiredPos));
newEntity.Input(newEntity, "SetOrigin", vtos(desiredPos));
newEntity.Respawn();
return (entity)newEntity;
}
/* Sends an input to the specified target. */
void
MapC_SendEntityInput(vector position, float radius, int maxDamage, int minDamage, optional entity attacker)
{
}
/* Damage Category */
void
MapC_RadiusDamage(entity target, entity activator, string inputName, string setValue)
{
NSEntity targetEntity = (NSEntity)target;
NSEntity theActivator = (NSEntity)activator;
targetEntity.Input(theActivator, inputName, setValue);
}
/* Sentient Category */
bool
MapC_IsAI(entity entityToCheck)
{
if (entityToCheck.flags & FL_MONSTER) {
return true;
}
return false;
}
bool
MapC_IsAlive(entity entityToCheck)
{
if (entityToCheck.takedamage != DAMAGE_NO) {
NSSurfacePropEntity livingEnt = (NSSurfacePropEntity)entityToCheck;
return livingEnt.IsAlive();
}
return false;
}
bool
MapC_IsGodMode(entity entityToCheck)
{
if (entityToCheck.flags & FL_GODMODE) {
return true;
}
return false;
}
bool
MapC_IsPlayer(entity entityToCheck)
{
if (entityToCheck.flags & FL_CLIENT) {
NSClient pl = (NSClient)entityToCheck;
return pl.IsPlayer();
}
return false;
}
bool
MapC_IsSentient(entity entityToCheck)
{
if (MapC_IsAI(entityToCheck) || MapC_IsPlayer(entityToCheck)) {
return true;
}
return false;
}

View File

@ -382,4 +382,15 @@ CSEv_DropWeapon(void)
player pl = (player)self;
Weapon_DropCurrentWeapon(pl);
}
#endif
#endif
void
CSEv_PlayerSwitchWeapon_i(int w)
{
player pl = (player)self;
if (pl.activeweapon != w) {
pl.activeweapon = w;
Weapons_Draw(pl);
}
}

View File

@ -44,6 +44,9 @@ public:
/* overrides */
virtual void OnRemoveEntity(void);
virtual float GetForwardSpeed(void);
virtual float GetSideSpeed(void);
virtual float GetBackSpeed(void);
#ifdef CLIENT
/** Client: Called on the client to give a chance to override input_* variables before networking them takes place. */

View File

@ -153,6 +153,24 @@ NSClient::IsPlayer(void)
return (false);
}
float
NSClient::GetForwardSpeed(void)
{
return cvar("cl_forwardspeed");
}
float
NSClient::GetSideSpeed(void)
{
return cvar("cl_sidespeed");
}
float
NSClient::GetBackSpeed(void)
{
return cvar("cl_backspeed");
}
#ifdef CLIENT
void
NSClient::ClientInputFrame(void)

View File

@ -33,6 +33,7 @@ public:
virtual void Physics_Fall(float);
virtual void Physics_Crouch(void);
virtual void Physics_Prone(void);
virtual void Physics_Jump(void);
virtual void Physics_CheckJump(float);
virtual void Physics_SetViewParms(void);
@ -48,6 +49,15 @@ public:
virtual bool IsDead(void);
virtual bool IsPlayer(void);
virtual void SharedInputFrame(void);
/** Overridable: Returns whether the client can sprint, with the command +sprint */
virtual bool CanSprint(void);
/** Overridable: Returns whether the client can prone, with the commands +prone and goprone */
virtual bool CanProne(void);
/** Overridable: Returns whether the client can crouch, with the commands +crouch and gocrouch */
virtual bool CanCrouch(void);
/** Overridable: Returns whether the client can lean, with the commands +leanleft and +leanright */
virtual bool CanLean(void);
/** Empty & shared between Client and Server. This is run on every player, every frame, to update their animation cycle. */
virtual void UpdatePlayerAnimation(float);
@ -127,6 +137,7 @@ private:
PREDICTED_FLOAT(w_idle_next)
PREDICTED_FLOAT(teleport_time)
PREDICTED_FLOAT(weapontime)
PREDICTED_FLOAT(m_flStamina)
PREDICTED_VECTOR(punchangle)
/* We can't use the default .items field, because FTE will assume

View File

@ -41,36 +41,52 @@ NSClientPlayer::IsRealSpectator(void)
bool
NSClientPlayer::IsDead(void)
{
if (health > 0)
return (false);
else
return (true);
return (health > 0) ? (false) : true;
}
bool
NSClientPlayer::IsPlayer(void)
{
if (HasFlags(FL_FAKESPEC))
return (false);
return (true);
return !HasVFlags(VFL_FAKESPEC);
}
bool
NSClientPlayer::IsFakeSpectator(void)
{
if (HasFlags(FL_FAKESPEC))
return (true);
return HasVFlags(VFL_FAKESPEC);
}
return (false);
bool
NSClientPlayer::CanSprint(void)
{
return g_pmoveVars.pm_runspeed > 0 ? (true) : false;
}
bool
NSClientPlayer::CanProne(void)
{
return g_pmoveVars.pm_proneheight > 0 ? (true) : false;
}
bool
NSClientPlayer::CanLean(void)
{
return (true);
}
bool
NSClientPlayer::CanCrouch(void)
{
return g_pmoveVars.pm_crouchheight > 0 ? (true) : false;
}
void
NSClientPlayer::PreFrame(void)
{
#ifdef CLIENT
if (Util_IsPaused())
if (Util_IsPaused()) {
return;
}
/* this is where a game/mod would decide to add more prediction rollback
* information. */
@ -110,8 +126,9 @@ void
NSClientPlayer::PostFrame(void)
{
#ifdef CLIENT
if (Util_IsPaused())
if (Util_IsPaused()) {
return;
}
/* give the game/mod a chance to roll back its values too */
PredictPostFrame();
@ -154,12 +171,12 @@ NSClientPlayer::ProcessInput(void)
rules.IntermissionEnd();
return;
} else if (IsAlive() == false) {
if (input_buttons & INPUT_BUTTON0)
if (input_buttons & INPUT_PRIMARY)
rules.PlayerRequestRespawn(this);
}
/* handle use button presses */
if (input_buttons & INPUT_BUTTON5)
if (input_buttons & INPUT_USE)
InputUse_Down();
else
InputUse_Up();
@ -186,11 +203,11 @@ NSClientPlayer::ProcessInput(void)
}
/* weapon system */
if (input_buttons & INPUT_BUTTON3)
if (input_buttons & INPUT_SECONDARY)
Weapons_Secondary((player)this);
else if (input_buttons & INPUT_BUTTON0)
else if (input_buttons & INPUT_PRIMARY)
Weapons_Primary((player)this);
else if (input_buttons & INPUT_BUTTON4)
else if (input_buttons & INPUT_RELOAD)
Weapons_Reload((player)this);
else
Weapons_Release((player)this);
@ -251,8 +268,8 @@ NSClientPlayer::predraw(void)
input_movevalues[0] = dotproduct(velocity, v_forward);
input_movevalues[1] = dotproduct(velocity, v_right);
input_movevalues[2] = dotproduct(velocity, v_up);
input_buttons = (flags & FL_JUMPRELEASED) ? 0 : INPUT_BUTTON2; /* this may not help that much... */
input_buttons |= (flags & FL_CROUCHING) ? INPUT_BUTTON8 : 0;
input_buttons = (flags & FL_JUMPRELEASED) ? 0 : INPUT_JUMP; /* this may not help that much... */
input_buttons |= IsCrouching() ? INPUT_CROUCH : 0;
input_angles = v_angle;
input_impulse = 0;
input_timelength = clframetime;
@ -273,7 +290,7 @@ NSClientPlayer::predraw(void)
RenderFire();
/* if we're inside of a vehicle, it may want to hide or show us regardless */
if (localplayer && HasFlags(FL_INVEHICLE)) {
if (localplayer && HasVFlags(VFL_INVEHICLE)) {
NSVehicle veh = (NSVehicle)vehicle;
if (veh)
@ -386,6 +403,10 @@ NSClientPlayer::UpdateAliveCam(void)
g_view.AddPunchAngle(punchangle);
}
var float autocvar_cl_forwardspeed = 190;
var float autocvar_cl_sidespeed = 152;
var float autocvar_cl_backspeed = 133;
/*
=================
NSClientPlayer::ClientInputFrame
@ -416,35 +437,40 @@ NSClientPlayer::ClientInputFrame(void)
if (serverkeyfloat("background") == 1)
return;
if (pSeat->m_iInputAttack2 == TRUE) {
input_buttons |= INPUT_BUTTON3;
if (pSeat->m_iInputAttack2 == true) {
input_buttons |= INPUT_SECONDARY;
}
if (pSeat->m_iInputReload == true) {
input_buttons |= INPUT_RELOAD;
}
if (pSeat->m_iInputUse == true) {
input_buttons |= INPUT_USE;
}
if (pSeat->m_iInputDuck == true) {
input_buttons |= INPUT_CROUCH;
}
if (pSeat->m_iInputProne == true) {
input_buttons |= INPUT_PRONE;
}
if (pSeat->m_iInputSprint == true) {
input_buttons |= INPUT_SPRINT;
}
if (pSeat->m_iInputJump == true) {
input_buttons |= INPUT_JUMP;
}
if (pSeat->m_iInputReload == TRUE) {
input_buttons |= INPUT_BUTTON4;
}
if (pSeat->m_iInputUse == TRUE) {
input_buttons |= INPUT_BUTTON5;
}
if (pSeat->m_iInputDuck == TRUE) {
input_buttons |= INPUT_BUTTON8;
}
if (pSeat->m_iInputExtra1 == TRUE) {
input_buttons |= INPUT_BUTTON6;
}
if (pSeat->m_iInputExtra2 == TRUE) {
input_buttons |= INPUT_BUTTON7;
/* IW style stance override */
if (pSeat->m_dForceStance == STANCE_CROUCH) {
input_buttons |= INPUT_CROUCH;
} else if (pSeat->m_dForceStance == STANCE_PRONE) {
input_buttons |= INPUT_PRONE;
}
/* The HUD needs more time */
if (pSeat->m_iHUDWeaponSelected) {
if ((input_buttons & INPUT_BUTTON0))
if ((input_buttons & INPUT_PRIMARY))
HUD_DrawWeaponSelect_Trigger();
else if ((input_buttons & INPUT_BUTTON3))
else if ((input_buttons & INPUT_SECONDARY))
pSeat->m_iHUDWeaponSelected = pSeat->m_flHUDWeaponSelectTime = 0;
pSeat->m_flInputBlockTime = time + 0.2;
@ -452,9 +478,9 @@ NSClientPlayer::ClientInputFrame(void)
/* prevent accidental input packets */
if (pSeat->m_flInputBlockTime > time) {
input_buttons &= ~INPUT_BUTTON0;
input_buttons &= ~INPUT_BUTTON3;
pSeat->m_iInputAttack2 = FALSE;
input_buttons &= ~INPUT_PRIMARY;
input_buttons &= ~INPUT_SECONDARY;
pSeat->m_iInputAttack2 = false;
return;
}
@ -465,7 +491,7 @@ NSClientPlayer::ClientInputFrame(void)
}
if (pSeat->m_iInputAttack) {
input_buttons |= INPUT_BUTTON0;
input_buttons |= INPUT_PRIMARY;
}
}
@ -477,6 +503,28 @@ NSClientPlayer::ClientInputFrame(void)
if (pSeat->m_flCameraTime > time) {
/* TODO: Supress the changing of view_angles/input_angles. */
}
vector movementDir = vectorNormalize(input_movevalues);
/* normalize movement values */
input_movevalues[0] = movementDir[0] * fabs(input_movevalues[0]);
input_movevalues[1] = movementDir[1] * fabs(input_movevalues[1]);
//if (mode_tempstate == 0)
if (input_movevalues[0] > 0)
if (pSeat->m_iSprinting == true) {
input_buttons |= INPUT_SPRINT;
input_movevalues[0] *= 1.5f;
input_movevalues[1] *= 1.5f;
input_movevalues[2] *= 1.5f;
/* prevent firing of weapons */
input_buttons &= ~INPUT_PRIMARY;
input_buttons &= ~INPUT_SECONDARY;
input_buttons &= ~INPUT_RELOAD;
} else {
input_buttons &= ~INPUT_SPRINT;
}
}
/*
@ -532,6 +580,7 @@ NSClientPlayer::ReceiveEntity(float new, float flChanged)
READENTITY_COORD(grapvelocity[1], PLAYER_VELOCITY)
READENTITY_COORD(grapvelocity[2], PLAYER_VELOCITY)
READENTITY_INT(flags, PLAYER_FLAGS)
READENTITY_INT(vv_flags, PLAYER_FLAGS)
READENTITY_INT(gflags, PLAYER_FLAGS)
READENTITY_INT(pmove_flags, PLAYER_FLAGS)
READENTITY_BYTE(activeweapon, PLAYER_WEAPON)
@ -553,6 +602,7 @@ NSClientPlayer::ReceiveEntity(float new, float flChanged)
READENTITY_FLOAT(punchangle[2], PLAYER_PUNCHANGLE)
READENTITY_FLOAT(viewzoom, PLAYER_VIEWZOOM)
READENTITY_FLOAT(teleport_time, PLAYER_TIMINGS)
READENTITY_FLOAT(m_flStamina, PLAYER_TIMINGS)
READENTITY_FLOAT(weapontime, PLAYER_TIMINGS)
READENTITY_FLOAT(w_attack_next, PLAYER_TIMINGS)
READENTITY_FLOAT(w_idle_next, PLAYER_TIMINGS)
@ -595,6 +645,7 @@ NSClientPlayer::PredictPreFrame(void)
SAVE_STATE(basevelocity)
SAVE_STATE(grapvelocity)
SAVE_STATE(flags)
SAVE_STATE(vv_flags)
SAVE_STATE(gflags)
SAVE_STATE(pmove_flags)
SAVE_STATE(activeweapon)
@ -610,6 +661,7 @@ NSClientPlayer::PredictPreFrame(void)
SAVE_STATE(punchangle)
SAVE_STATE(viewzoom)
SAVE_STATE(teleport_time)
SAVE_STATE(m_flStamina)
SAVE_STATE(weapontime)
SAVE_STATE(w_attack_next)
SAVE_STATE(w_idle_next)
@ -641,6 +693,7 @@ NSClientPlayer::PredictPostFrame(void)
ROLL_BACK(basevelocity)
ROLL_BACK(grapvelocity)
ROLL_BACK(flags)
ROLL_BACK(vv_flags)
ROLL_BACK(gflags)
ROLL_BACK(pmove_flags)
ROLL_BACK(activeweapon)
@ -656,6 +709,7 @@ NSClientPlayer::PredictPostFrame(void)
ROLL_BACK(punchangle)
ROLL_BACK(viewzoom)
ROLL_BACK(teleport_time)
ROLL_BACK(m_flStamina)
ROLL_BACK(weapontime)
ROLL_BACK(w_attack_next)
ROLL_BACK(w_idle_next)
@ -691,6 +745,7 @@ NSClientPlayer::Save(float handle)
SaveVector(handle, "angles", angles);
SaveFloat(handle, "colormap", colormap);
SaveFloat(handle, "flags", flags);
SaveFloat(handle, "vv_flags", vv_flags);
SaveFloat(handle, "gflags", gflags);
SaveFloat(handle, "viewzoom", viewzoom);
SaveVector(handle, "view_ofs", view_ofs);
@ -702,6 +757,7 @@ NSClientPlayer::Save(float handle)
SaveFloat(handle, "w_attack_next", w_attack_next);
SaveFloat(handle, "w_idle_next", w_idle_next);
SaveFloat(handle, "teleport_time", teleport_time);
SaveFloat(handle, "m_flStamina", m_flStamina);
SaveInt(handle, "weaponframe", weaponframe);
SaveFloat(handle, "weapontime", weapontime);
SaveInt(handle, "g_items", g_items);
@ -740,6 +796,9 @@ NSClientPlayer::Restore(string strKey, string strValue)
case "flags":
flags = ReadFloat(strValue);
break;
case "vv_flags":
vv_flags = ReadFloat(strValue);
break;
case "gflags":
gflags = ReadFloat(strValue);
break;
@ -770,6 +829,9 @@ NSClientPlayer::Restore(string strKey, string strValue)
case "teleport_time":
teleport_time = ReadFloat(strValue);
break;
case "m_flStamina":
m_flStamina = ReadFloat(strValue);
break;
case "weaponframe":
weaponframe = ReadInt(strValue);
break;
@ -821,7 +883,7 @@ NSClientPlayer::MakeTempSpectator(void)
SetMovetype(MOVETYPE_NOCLIP);
SetTakedamage(DAMAGE_NO);
maxspeed = 250;
flags |= FL_FAKESPEC;
AddVFlags(VFL_FAKESPEC);
max_health = health = 0;
armor = 0;
g_items = 0;
@ -860,7 +922,7 @@ NSClientPlayer::Death(void)
SetVelocity([0,0,0]);
SetGravity(1.0f);
customphysics = Empty;
SetCanBleed(false);
DisableBleeding();
setsize(this, [0,0,0], [0,0,0]);
forceinfokey(this, "*deaths", ftos(deaths));
forceinfokey(this, "*dead", "1");
@ -879,10 +941,14 @@ void
NSClientPlayer::MakePlayer(void)
{
classname = "player";
flags = FL_CLIENT;
health = max_health = 100;
armor = 0;
g_items = 0;
AddFlags(FL_CLIENT);
RemoveVFlags(VFL_FAKESPEC);
if (health <= 0) {
health = max_health = 100;
armor = 0;
}
activeweapon = 0;
effects = 0;
alpha = 1.0f;
@ -895,12 +961,13 @@ NSClientPlayer::MakePlayer(void)
SetGravity(1.0f);
SendFlags = UPDATE_ALL;
customphysics = Empty;
SetCanBleed(true);
EnableBleeding();
scale = 1.0f;
SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
forceinfokey(this, "*spectator", "0");
forceinfokey(this, "*deaths", ftos(deaths));
forceinfokey(this, "*dead", "0");
forceinfokey(this, "*spec", "0");
}
void
@ -924,7 +991,7 @@ at the top of player::EvaluateEntity
void
NSClientPlayer::EvaluateEntity(void)
{
pvsflags = (flags & FL_FAKESPEC) ? 0 : PVSF_IGNOREPVS;
pvsflags = !HasVFlags(VFL_FAKESPEC) ? 0 : PVSF_IGNOREPVS;
EVALUATE_FIELD(modelindex, PLAYER_MODELINDEX)
EVALUATE_FIELD(colormap, PLAYER_MODELINDEX)
@ -956,6 +1023,7 @@ NSClientPlayer::EvaluateEntity(void)
EVALUATE_VECTOR(grapvelocity, 1, PLAYER_VELOCITY)
EVALUATE_VECTOR(grapvelocity, 2, PLAYER_VELOCITY)
EVALUATE_FIELD(flags, PLAYER_FLAGS)
EVALUATE_FIELD(vv_flags, PLAYER_FLAGS)
EVALUATE_FIELD(gflags, PLAYER_FLAGS)
EVALUATE_FIELD(pmove_flags, PLAYER_FLAGS)
EVALUATE_FIELD(activeweapon, PLAYER_WEAPON)
@ -977,6 +1045,7 @@ NSClientPlayer::EvaluateEntity(void)
EVALUATE_VECTOR(punchangle, 2, PLAYER_PUNCHANGLE)
EVALUATE_FIELD(viewzoom, PLAYER_VIEWZOOM)
EVALUATE_FIELD(teleport_time, PLAYER_TIMINGS)
EVALUATE_FIELD(m_flStamina, PLAYER_TIMINGS)
EVALUATE_FIELD(weapontime, PLAYER_TIMINGS)
EVALUATE_FIELD(w_attack_next, PLAYER_TIMINGS)
EVALUATE_FIELD(w_idle_next, PLAYER_TIMINGS)
@ -1028,6 +1097,7 @@ NSClientPlayer::SendEntity(entity ePEnt, float flChanged)
SENDENTITY_COORD(grapvelocity[1], PLAYER_VELOCITY)
SENDENTITY_COORD(grapvelocity[2], PLAYER_VELOCITY)
SENDENTITY_INT(flags, PLAYER_FLAGS)
SENDENTITY_INT(vv_flags, PLAYER_FLAGS)
SENDENTITY_INT(gflags, PLAYER_FLAGS)
SENDENTITY_INT(pmove_flags, PLAYER_FLAGS)
SENDENTITY_BYTE(activeweapon, PLAYER_WEAPON)
@ -1049,6 +1119,7 @@ NSClientPlayer::SendEntity(entity ePEnt, float flChanged)
SENDENTITY_FLOAT(punchangle[2], PLAYER_PUNCHANGLE)
SENDENTITY_FLOAT(viewzoom, PLAYER_VIEWZOOM)
SENDENTITY_FLOAT(teleport_time, PLAYER_TIMINGS)
SENDENTITY_FLOAT(m_flStamina, PLAYER_TIMINGS)
SENDENTITY_FLOAT(weapontime, PLAYER_TIMINGS)
SENDENTITY_FLOAT(w_attack_next, PLAYER_TIMINGS)
SENDENTITY_FLOAT(w_idle_next, PLAYER_TIMINGS)
@ -1104,7 +1175,7 @@ A wrapper to cleanly reset 'self' as to not mess up the QC VM
void
_NSClientPlayer_useworkaround(entity eTarget)
{
eActivator = self;
eActivator = (NSEntity)self;
entity eOldSelf = self;
self = eTarget;
self.PlayerUse();
@ -1121,7 +1192,7 @@ A wrapper to cleanly reset 'self' as to not mess up the QC VM
void
_NSClientPlayer_unuseworkaround(entity eTarget)
{
eActivator = self;
eActivator = (NSEntity)self;
entity eOldSelf = self;
self = eTarget;
if (self.PlayerUseUnpressed)
@ -1140,9 +1211,9 @@ looks for an entity that has the .PlayerUse field set to a function and calls it
void
NSClientPlayer::InputUse_Down(void)
{
if (health <= 0) {
if (IsDead()) {
return;
} else if (!(flags & FL_USE_RELEASED)) {
} else if (!(vv_flags & VFL_USE_RELEASED)) {
return;
}
@ -1175,17 +1246,17 @@ NSClientPlayer::InputUse_Down(void)
/* TODO: maybe eRad will return something in the future that'll suppress a successfull use? */
if (eRad && found_use == true) {
flags &= ~FL_USE_RELEASED;
RemoveVFlags(VFL_USE_RELEASED);
_NSClientPlayer_useworkaround(eRad);
last_used = eRad;
/* Some entities want to support Use spamming */
if (HasFlags(FL_USE_RELEASED) == false) {
if (HasVFlags(VFL_USE_RELEASED) == false) {
StartSoundDef("Player.WeaponSelected", CHAN_ITEM, false);
}
} else {
StartSoundDef("Player.DenyWeaponSelection", CHAN_ITEM, false);
flags &= ~FL_USE_RELEASED;
RemoveVFlags(VFL_USE_RELEASED);
}
}
@ -1199,10 +1270,10 @@ Called when we let go of the +use button
void
NSClientPlayer::InputUse_Up(void)
{
if (HasFlags(FL_USE_RELEASED) == false) {
if (HasVFlags(VFL_USE_RELEASED) == false) {
_NSClientPlayer_unuseworkaround(last_used);
last_used = world;
flags |= FL_USE_RELEASED;
AddVFlags(VFL_USE_RELEASED);
}
}
#endif
@ -1240,7 +1311,7 @@ NSClientPlayer::Footsteps_Update(void)
return;
} else {
/* make it so we step once we land */
if (HasFlags(FL_ONGROUND | FL_ONLADDER) == false) {
if (HasFlags(FL_ONGROUND) == false && HasVFlags(VFL_ONLADDER) == false) {
step_time = 0.0f;
return;
}
@ -1254,9 +1325,9 @@ NSClientPlayer::Footsteps_Update(void)
tex_name = getsurfacetexture(trace_ent, getsurfacenearpoint(trace_ent, trace_endpos));
/* don't step in air */
if (HasFlags(FL_ONGROUND | FL_ONLADDER) == false) {
if (HasFlags(FL_ONGROUND) == false && HasVFlags(VFL_ONLADDER) == false) {
return;
} else if (HasFlags(FL_ONLADDER) && HasFlags(FL_ONGROUND) == false) { /* play ladder sounds */
} else if (HasVFlags(VFL_ONLADDER) && HasFlags(FL_ONGROUND) == false) { /* play ladder sounds */
if (step)
StartSoundDef("step_ladder.left", CHAN_BODY, true);
else
@ -1265,7 +1336,7 @@ NSClientPlayer::Footsteps_Update(void)
/* switch between feet */
step = 1 - step;
return;
} else if (HasFlags(FL_ONLADDER) && HasFlags(FL_ONGROUND)) { /* at a ladder, but not moving */
} else if (HasVFlags(VFL_ONLADDER) && HasFlags(FL_ONGROUND)) { /* at a ladder, but not moving */
return;
}

View File

@ -66,11 +66,11 @@ void
NSClientSpectator::ProcessInput(void)
{
#ifdef SERVER
if (input_buttons & INPUT_BUTTON0) {
if (input_buttons & INPUT_PRIMARY) {
InputNext();
} else if (input_buttons & INPUT_BUTTON3) {
} else if (input_buttons & INPUT_SECONDARY) {
InputPrevious();
} else if (input_buttons & INPUT_BUTTON2) {
} else if (input_buttons & INPUT_JUMP) {
InputMode();
} else {
spec_flags &= ~SPECFLAG_BUTTON_RELEASED;
@ -163,8 +163,22 @@ NSClientSpectator::ClientInputFrame(void)
}
/* background maps have no input */
if (serverkeyfloat("background") == 1)
if (serverkeyfloat("background") == 1) {
input_impulse = 0;
input_buttons = 0;
input_movevalues = g_vec_null;
return;
}
vector movementDir = vectorNormalize(input_movevalues);
/* normalize movement values */
if (movementDir[0] > 0)
input_movevalues[0] = movementDir[0] * GetForwardSpeed();
else
input_movevalues[0] = movementDir[0] * GetBackSpeed();
input_movevalues[1] = movementDir[1] * GetSideSpeed();
}
void

View File

@ -61,6 +61,7 @@ private:
string m_oldModel; /**< contains the model that the entity spawned with */
float m_oldSolid; /**< contains the collision type the entity spawned with */
bool m_bIsBrush;
vector m_vecEditorColor;
PREDICTED_VECTOR_N(origin)
PREDICTED_VECTOR_N(angles)
@ -72,11 +73,13 @@ private:
PREDICTED_FLOAT_N(movetype)
PREDICTED_FLOAT_N(scale)
PREDICTED_FLOAT_N(flags)
PREDICTED_FLOAT_N(vv_flags)
PREDICTED_VECTOR_N(velocity)
PREDICTED_VECTOR_N(avelocity)
#ifdef SERVER
string m_parent;
string m_parent_old;
string m_parent_attachment;
PREDICTED_FLOAT_N(frame)
PREDICTED_FLOAT_N(skin)
@ -149,6 +152,9 @@ public:
/** Unsets any any angle related values within the entity. */
nonvirtual void ClearAngles(void);
/** Simulates the press of the use/activate key, with the passed entity being the activator. */
nonvirtual void UseBy(entity);
/** Forces the entity to re-network updates to all clients. */
nonvirtual void ForceNetworkUpdate(void);
#endif
@ -157,9 +163,9 @@ public:
/** Sets the whole effects field. Check the effects_t enum for available effects.*/
nonvirtual void SetEffects(float);
/** Appends one or more effects to the entity. Check the effects_t enum for available effects.*/
nonvirtual void AddEffects(float);
nonvirtual void AddEffects(effects_t);
/** Removes one or more effects from the entity. Check the effects_t enum for available effects.*/
nonvirtual void RemoveEffects(float);
nonvirtual void RemoveEffects(effects_t);
/** Sets the framegroup sequence of the entity. Must be positive.*/
nonvirtual void SetFrame(float);
/** Sets the skingroup of the entity. Must be positive. */
@ -171,7 +177,6 @@ public:
/** Sets the movement velocity of the given entity. */
nonvirtual void SetVelocity(vector);
/** Adds onto the existing angular velocity. */
nonvirtual void AddAngularVelocity(vector);
/** Adds onto the existing velocity. */
@ -201,10 +206,14 @@ public:
/** Sets the bounding box size of the entity.
This affects both collision and rendering bounds checking. */
nonvirtual void SetSize(vector,vector);
/** Adds one or more special flags to the entity. */
/** Adds one or more engine specific flags to the entity. */
nonvirtual void AddFlags(float);
/** Remove one or more special flags from the entity. */
/** Remove one or more engine specific flags from the entity. */
nonvirtual void RemoveFlags(float);
/** Adds one or more nuclide specific flags to the entity. */
nonvirtual void AddVFlags(float);
/** Remove one or more nuclide specific flags from the entity. */
nonvirtual void RemoveVFlags(float);
/** Turns to the specified angle. */
nonvirtual void TurnTo(float);
@ -275,10 +284,14 @@ public:
/** Returns the absolute bounding box maxs of the entity,
instead of being relative to the world position. */
nonvirtual vector GetAbsoluteMaxs(void);
/** Returns a flag bitfield that the entity associates with. */
/** Returns an engine flags bitfield that the entity associates with. */
nonvirtual float GetFlags(void);
/** Returns true if the entity has the specified flags. */
/** Returns true if the entity has the specified engine flags. */
nonvirtual float HasFlags(float);
/** Returns a nuclide flags bitfield that the entity associates with. */
nonvirtual float GetVFlags(void);
/** Returns true if the entity has the specified, nuclide specific, flags. */
nonvirtual float HasVFlags(float);
/** Returns an absolute value of when the entity will be think again.
Any result should be tested against `::GetTime()`. */
nonvirtual float GetNextThinkTime(void);
@ -286,6 +299,8 @@ public:
nonvirtual bool IsThinking(void);
/** When called, will unset anything related to ongoing think operations. */
nonvirtual void ReleaseThink(void);
/** When called, will make the entity think busy for the specified amount of time. In that time, IsThinking() will return true. */
nonvirtual void ThinkBusy(float);
/** When called, will clear anything related to physical movement on the entity. */
nonvirtual void ClearVelocity(void);
@ -296,7 +311,6 @@ public:
nonvirtual void Hide(void);
/** Returns if the entity is currently being hidden explicitly. */
nonvirtual bool IsHidden(void);
/** Returns if the entity is solid or non-solid */
nonvirtual bool IsSolid(void);

File diff suppressed because it is too large Load Diff

View File

@ -14,14 +14,50 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef SERVER
/* PICKUP ITEMS */
/** id Tech 4 keys to support:
*/
/*! \brief This entity class represents non-player characters. */
/*!QUAKED NSMonster (0 0.8 0.8) (-16 -16 0) (16 16 72) WAITTILLSEEN GAG MONSTERCLIP x PRISONER x IGNOREPLAYER WAITFORSCRIPT PREDISASTER FADECORPSE MULTIPLAYER FALLING HORDE
# OVERVIEW
Represents any item within the players' inventory.
These can be used, or be dormant.
# KEYS
- "targetname" : Name
- "model" : world model.
- "model_view" : view model.
- "model_world - same as model.
- "inv_name" : Fancy title. Can be a localized string.
- "inv_weapon" : name of the weapon to give on pickup. can be the same as this entitydef.
- "inv_item" : item number. must be unique.
- "weapon_scriptobject" : mapC progs with the weapon code within.
- "ammoType" : name of the ammo type def entry which the gun uses
- "ammoRequired" : set to 1 if we require ammo.
- "clipSize" : maximum clip size
- "mtr_flashShader" : muzzleflash material to Use.
- "model_flash" : muzzleflash model/sprite to use.
- "flashColor" : muzzleflash dlight color
- "flashRadius" : muzzleflash dlight radius
- "def_dropItem" : when this item is dropped from someones inventory, will spawn this entityDef item instead.
- "snd_acquire" : pickup noise
- "snd_respawn" : respawn noise
- "snd_hum" : idle shader
- "smoke_muzzle" : smoke particle effect name
- "continuousSmoke" : whether the particle effect is continous
- "clipSizeDefault" : CUSTOM: Default clip size on pickup.
*/
class NSItem:NSRenderableEntity
{
public:
void NSItem(void);
/* overrides */
#ifdef SERVER
virtual void Spawned(void);
virtual void Touch(entity);
virtual void Respawn(void);
@ -35,8 +71,9 @@ public:
nonvirtual bool GetFloating(void);
nonvirtual void SetSpinning(bool);
nonvirtual bool GetSpinning(void);
nonvirtual void PickupRespawn(void);
#endif
private:
int m_iClip;
@ -48,5 +85,5 @@ private:
string m_sndRespawn;
int m_bFloating;
bool m_bSpins;
};
#endif
string m_strInvWeapon;
};

View File

@ -14,10 +14,10 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef SERVER
void
NSItem::NSItem(void)
{
#ifdef SERVER
m_iClip = -1;
m_iWasDropped = 0i;
m_iInvItem = 0i;
@ -25,8 +25,10 @@ NSItem::NSItem(void)
m_sndRespawn = __NULL__;
m_bFloating = false;
m_bSpins = false;
#endif
}
#ifdef SERVER
void
NSItem::Spawned(void)
{
@ -74,6 +76,9 @@ void
NSItem::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "inv_weapon":
m_strInvWeapon = ReadString(strValue);
break;
case "inv_item":
m_iInvItem = ReadInt(strValue);
break;
@ -112,6 +117,7 @@ NSItem::Save(float handle)
SaveString(handle, "m_sndRespawn", m_sndRespawn);
SaveBool(handle, "m_bFloating", m_bFloating);
SaveBool(handle, "m_bSpins", m_bSpins);
SaveString(handle, "m_strInvWeapon", m_strInvWeapon);
}
void
@ -139,6 +145,9 @@ NSItem::Restore(string strKey, string strValue)
case "m_bSpins":
m_bSpins = ReadBool(strValue);
break;
case "m_strInvWeapon":
m_strInvWeapon = ReadString(strValue);
break;
default:
super::Restore(strKey, strValue);
break;
@ -148,14 +157,18 @@ NSItem::Restore(string strKey, string strValue)
void
NSItem::Touch(entity eToucher)
{
NSClientPlayer pl = (NSClientPlayer)eToucher;
if (eToucher.classname != "player") {
return;
}
#if 0
/* don't remove if AddItem fails */
if (Weapons_AddItem((player)eToucher, m_iInvItem, m_iClip) == FALSE) {
if (pl.GiveWeapon(m_strInvWeapon) == false) {
return;
}
#endif
Logging_Pickup(eToucher, this, __NULL__);
StartSoundDef(m_sndAcquire, CHAN_ITEM, true);
@ -215,4 +228,45 @@ NSItem::PickupRespawn(void)
Respawn();
StartSoundDef(m_sndRespawn, CHAN_ITEM, true);
}
void
NSItem::Draw(void)
{
}
void
NSItem::Holster(void)
{
}
void
NSItem::PrimaryAttack(void)
{
}
void
NSItem::SecondaryAttack(void)
{
}
void
NSItem::Reload(void)
{
}
void
NSItem::Release(void)
{
}
void
NSItem::OnPickup(void)
{
}
void
NSItem::OnInventoryUse(void)
{
}
#endif

View File

@ -334,6 +334,7 @@ public:
//virtual void Hide(void);
virtual void Spawned(void);
virtual void Respawn(void);
virtual void Input(entity,string,string);
virtual void Pain(void);
virtual void Death(void);
virtual void Physics(void);
@ -597,6 +598,8 @@ private:
float m_flLeapDamage;
bool m_bLeapAttacked;
float m_flForceSequence;
float m_flSkin;
bool m_bGagged;
nonvirtual void _LerpTurnToEnemy(void);
nonvirtual void _LerpTurnToPos(vector);

View File

@ -92,6 +92,8 @@ NSMonster::NSMonster(void)
m_flLeapDamage = 0;
m_bLeapAttacked = false;
maxspeed = 1024;
m_bGagged = false;
m_flSkin = 0;
#endif
}
@ -519,7 +521,7 @@ NSMonster::Sound(string msg)
void
NSMonster::Gib(void)
{
vector vecDir = vectoangles(GetOrigin() - g_dmg_vecLocation);
vector vecDir = vectorToAngles(GetOrigin() - g_dmg_vecLocation);
SetState(MONSTER_DEAD);
SetTakedamage(DAMAGE_NO);
@ -536,8 +538,12 @@ NSMonster::FallNoise(void)
void
NSMonster::IdleNoise(void)
{
if (m_flIdleNext > time)
if (m_bGagged == true) {
return;
}
if (m_flIdleNext > time) {
return;
}
StartSoundDef(m_sndIdle, CHAN_VOICE, true);
m_flIdleNext = time + random(m_flIdleMin, m_flIdleMax);
@ -546,6 +552,10 @@ NSMonster::IdleNoise(void)
void
NSMonster::AlertNoise(void)
{
if (m_bGagged == true) {
return;
}
StartSoundDef(m_sndSight, CHAN_VOICE, true);
}
@ -669,17 +679,15 @@ NSMonster::SeeThink(void)
if (m_eLookAt) {
vector vecDelta;
makevectors( angles );
vecDelta = normalize( (m_eLookAt.origin + m_eLookAt.view_ofs) - GetEyePos() );
m_flHeadYaw = (vecDelta * v_right) * -60;
m_flHeadYaw = (vecDelta * anglesToRight(angles)) * -60;
//print(sprintf("head yaw: %f %v\n", m_flHeadYaw, vecDelta));
/* this will make the actor 'aim" at the target */
{
makevectors(v_angle);
vector tmp = vectoangles(v_forward);
vector tmp = vectorToAngles(anglesToForward(v_angle));
subblendfrac = tmp[0] / 90;
bonecontrol1 = Math_Lerp(bonecontrol1, m_flHeadYaw, frametime * 15.0f); /* head turning */
bonecontrol1 = lerp(bonecontrol1, m_flHeadYaw, frametime * 15.0f); /* head turning */
}
}
@ -707,8 +715,7 @@ NSMonster::SeeThink(void)
/* enemy is not valid anymore, reset it, clear route and search for new enemy */
RouteClear();
makevectors(angles);
RouteToPosition(m_eEnemy.origin + (v_forward * -64));
RouteToPosition(m_eEnemy.origin + (anglesToForward(angles) * -64));
m_flSequenceSpeed = GetWalkSpeed();
SetState(MONSTER_ALERT);
@ -743,9 +750,8 @@ NSMonster::SeeThink(void)
continue;
/* first, is the potential enemy in our field of view? */
makevectors(angles);
vector v = normalize(w.origin - GetEyePos());
float flDot = v * v_forward;
float flDot = v * anglesToForward(angles);
if (flDot < SeeFOV()/180)
continue;
@ -793,58 +799,38 @@ NSMonster::GetYawSpeed(void)
void
NSMonster::_LerpTurnToYaw(vector turnYaw)
{
#if 0
angles[1] = input_angles[1] = v_angle[1] = turnYaw[1];
#else
float turnSpeed = GetYawSpeed();
vector vecWishAngle = turnYaw;
float yawDiff = anglesub(turnYaw[1], v_angle[1]);
vector oldAngle = angles;
vector angleDelta;
float oldYaw = angles[1];
float yawDiff = 0.0f;
yaw_speed = GetYawSpeed() * (frametime * 5);
ideal_yaw = turnYaw[1];
changeyaw();
angleDelta = angleDifference(oldAngle, angles);
input_angles[1] = v_angle[1] = angles[1];
/* anything but small turns? halt the player */
if (fabs(yawDiff) > 5) {
input_movevalues = g_vec_null;
}
///printf("yawDiff: %f\n", angleDelta[1]);
if (fabs(yawDiff) > 45) {
velocity = g_vec_null;
input_movevalues = g_vec_null;
if (fabs(angleDelta[1]) > 1.0f) {
/* wasn't turning before */
if (m_bTurning == false) {
if (m_bTurning == false)
if (yawDiff < 0) {
SetFrame(FramegroupForAct(ACT_TURN_RIGHT));
} else {
SetFrame(FramegroupForAct(ACT_TURN_LEFT));
if (yawDiff < 0) {
AnimPlay(FramegroupForAct(ACT_TURN_RIGHT));
} else {
AnimPlay(FramegroupForAct(ACT_TURN_LEFT));
}
}
m_bTurning = true;
} else {
m_bTurning = false;
}
/* min/max out the diff */
if (yawDiff > 0) {
v_angle[1] += turnSpeed * frametime;
if (v_angle[1] > vecWishAngle[1])
v_angle[1] = vecWishAngle[1];
} else if (yawDiff < 0) {
v_angle[1] -= turnSpeed * frametime;
if (v_angle[1] < vecWishAngle[1])
v_angle[1] = vecWishAngle[1];
}
/* fix angles */
makevectors(v_angle);
vecWishAngle = vectoangles( v_forward );
angles[1] = input_angles[1] = v_angle[1] = vecWishAngle[1];
#endif
}
void
NSMonster::_LerpTurnToPos(vector turnPos)
{
vector vecWishAngle = vectoangles(turnPos - origin);
vector vecWishAngle = vectorToAngles(turnPos - origin);
_LerpTurnToYaw(vecWishAngle);
}
@ -868,7 +854,7 @@ NSMonster::_LerpTurnToEnemy(void)
enemyEyePos = (m_eEnemy.origin + m_eEnemy.view_ofs);
dirAim = vectoangles(enemyEyePos - GetEyePos());
dirAim = vectorToAngles(enemyEyePos - GetEyePos());
v_angle[0] = dirAim[0];
}
@ -1179,8 +1165,9 @@ NSMonster::FreeState(void)
if (findKT) {
NSMonsterLog("Killing %S", m_strSequenceKillTarget);
findKT.Destroy();
findKT.targetname = "";
} else {
NSError("Could not remove %S!", m_strSequenceKillTarget);
EntError("Unable to find %S for removal", m_strSequenceKillTarget);
}
m_strSequenceKillTarget = __NULL__;
@ -1270,35 +1257,36 @@ NSMonster::RouteEnded(void)
void
NSMonster::WalkRoute(void)
{
vector wishAngle = input_angles;
/* 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;
wishAngle = vectorToAngles(m_eEnemy.origin - origin);
wishAngle[0] = wishAngle[2] = 0;
} else if (IsOnRoute()) {
input_angles = GetRouteDirection();
input_angles[0] = input_angles[2] = 0;
wishAngle = GetRouteDirection();
wishAngle[0] = wishAngle[2] = 0;
input_movevalues = GetRouteMovevalues() * m_flSequenceSpeed;
/* is something in our way? */
makevectors(input_angles);
tracebox(origin, mins, maxs, origin + v_forward * 256, MOVE_NORMAL, this);
tracebox(origin, [-16, -16, -16], [16, 16, 16], origin + anglesToForward(wishAngle) * 256, MOVE_NORMAL, this);
/* indeed it is */
if (trace_fraction < 1.0f) {
vector testOrg = origin + (v_right * 32);
vector testOrg = origin + (anglesToRight(wishAngle) * 32) + anglesToForward(wishAngle) * 128;
testOrg[2] += mins[2] + 18.0f; /* test at feet level */
traceline(testOrg, testOrg + v_forward * 256, MOVE_NORMAL, this);
traceline(origin, testOrg, MOVE_NORMAL, this);
/* is space free to the right? */
if (trace_fraction == 1.0) {
input_movevalues[1] = m_flSequenceSpeed * 0.25f;
} else {
testOrg = origin - (v_right * 32);
testOrg = origin - (anglesToRight(wishAngle) * 32) + anglesToForward(wishAngle) * 128;
testOrg[2] += mins[2] + 18.0f; /* test at feet level */
traceline(testOrg, testOrg + v_forward * 256, MOVE_NORMAL, this);
traceline(origin, testOrg, MOVE_NORMAL, this);
/* is space free to the left? */
if (trace_fraction == 1.0)
@ -1307,19 +1295,14 @@ NSMonster::WalkRoute(void)
}
} else if (GetState() == MONSTER_CHASING && m_eEnemy) {
/* we've got 'em in our sights, just need to walk closer */
input_angles = vectoangles(m_eEnemy.origin - origin);
input_angles[0] = input_angles[2] = 0;
wishAngle = vectorToAngles(m_eEnemy.origin - origin);
wishAngle[0] = wishAngle[2] = 0;
input_movevalues = [GetChaseSpeed(), 0, 0];
} else
return;
/* don't move while turning. */
if (m_bTurning == true) {
input_movevalues = [0,0,0];
}
/* yaw interpolation */
_LerpTurnToYaw(input_angles);
_LerpTurnToYaw(wishAngle);
}
void
@ -1460,8 +1443,6 @@ NSMonster::RunAI(void)
AttackThink();
}
void PMoveCustom_RunPlayerPhysics(entity target);
void PMoveCustom_RunCrouchPhysics(entity target);
void
NSMonster::Physics(void)
{
@ -1498,8 +1479,10 @@ NSMonster::Physics(void)
/* we're ending a scripted sequence, so play its animation */
if (GetSequenceState() == SEQUENCESTATE_ENDING) {
angles[1] = input_angles[1] = m_vecSequenceAngle[1];
SetFrame(m_flSequenceEnd);
_LerpTurnToYaw(m_vecSequenceAngle);
if (m_bTurning == false)
SetFrame(m_flSequenceEnd);
} else {
/* if still alive... */
if (IsAlive()) {
@ -1523,12 +1506,13 @@ NSMonster::Physics(void)
hitcontentsmaski = CONTENTBITS_MONSTER;
if (CanCrouch())
PMoveCustom_RunCrouchPhysics(this);
else
PMoveCustom_RunPlayerPhysics(this);
/* don't move while turning. */
if (m_bTurning == true) {
input_movevalues = [0,0,0];
}
SetOrigin(origin);
/* complete the move */
Physics_Run();
}
if (!(GetFlags() & FL_ONGROUND) && velocity[2] < -415) {
@ -1578,8 +1562,7 @@ NSMonster::Touch(entity eToucher)
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);
tracebox(origin, mins, maxs, origin + (anglesToForward([0, yaw, 0]) * 128.0f), FALSE, this);
if (trace_startsolid) {
bestYaw = random(0, 360);
@ -1818,10 +1801,7 @@ NSMonster::Respawn(void)
setorigin_safe(this, origin);
}
v_angle = GetSpawnAngles();
v_angle[0] = Math_FixDelta(v_angle[0]);
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = Math_FixDelta(v_angle[2]);
v_angle = fixAngle(GetSpawnAngles());
AddFlags(FL_MONSTER);
SetTakedamage(DAMAGE_AIM);
@ -1830,7 +1810,7 @@ NSMonster::Respawn(void)
SetHealth(base_health);
m_eEnemy = __NULL__;
m_iFlags = 0x0;
SetCanBleed(true);
EnableBleeding();
customphysics = Physics;
SetAngles(v_angle);
@ -1841,6 +1821,7 @@ NSMonster::Respawn(void)
SetEyePos([0, 0, m_flEyeHeight]);
SetOrigin(GetSpawnOrigin());
ScheduleThink(AdjustSpawnPos, 0.0f);
SetSkin(m_flSkin);
if (HasSpawnFlags(MSF_MONSTERCLIP)) {
hitcontentsmaski = CONTENTBITS_BOXSOLID | CONTENTBIT_MONSTERCLIP;
@ -1864,6 +1845,12 @@ NSMonster::Respawn(void)
SetFrame(_m_flFrame);
}
if (HasSpawnFlags(MSF_GAG)) {
m_bGagged = true;
} else {
m_bGagged = false;
}
/* automatically start */
if (!targetname)
if (HasTriggerTarget() == true) {
@ -1871,6 +1858,31 @@ NSMonster::Respawn(void)
}
}
void
NSMonster::Input( entity entityActivator, string inputName, string dataField )
{
switch (inputName) {
case "Sleep":
customphysics = __NULL__;
ReleaseThink();
break;
case "Wake":
customphysics = Physics;
break;
case "StartScripting":
m_iSequenceState = SEQUENCESTATE_IDLE;
break;
case "GagEnable":
m_bGagged = true;
break;
case "GagDisable":
m_bGagged = false;
break;
default:
super::Input(entityActivator, inputName, dataField);
}
}
void
NSMonster::Trigger(entity act, triggermode_t state)
{
@ -2046,6 +2058,9 @@ NSMonster::SpawnKey(string strKey, string strValue)
case "frame":
_m_flFrame = ReadFloat(strValue);
break;
case "skin":
m_flSkin = ReadFloat(strValue);
break;
case "sequence":
m_flForceSequence = ReadFloat(strValue);
break;
@ -2171,19 +2186,6 @@ NSMonster::predraw(void)
render = super::predraw();
/* are we inside of an interpolation? */
if (frame != frame2) {
/* we're done lerping */
if (lerpfrac <= 0.0f)
frame2 = frame;
lerpfrac -= frametime * 4.0f;
} else {
/* make sure we're set up for next lerp */
lerpfrac = 1.0f;
frame2time = frame1time;
}
_RenderDebugViewCone();
return render;
@ -2261,11 +2263,10 @@ NSMonster::_RenderDebugViewCone(void)
if (autocvar(r_showViewCone, 0) == 0)
return;
makevectors(angles);
testOrg = pSeat->m_ePlayer.origin;
v = normalize(testOrg - GetEyePos());
flDot = v * v_forward;
flDot = v * anglesToForward(angles);
/* not inside our FoV at all */
if (flDot < 90.0f/180) {

Some files were not shown because too many files have changed in this diff Show More