diff --git a/Documentation/Bots/BotOverview.md b/Documentation/Bots/BotOverview.md index 4654b05a..0c4abf36 100644 --- a/Documentation/Bots/BotOverview.md +++ b/Documentation/Bots/BotOverview.md @@ -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. \ No newline at end of file +## 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. diff --git a/Documentation/EntityGuide.md b/Documentation/EntityGuide.md index e03bcef8..9ac25746 100644 --- a/Documentation/EntityGuide.md +++ b/Documentation/EntityGuide.md @@ -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) diff --git a/Documentation/MapC.md b/Documentation/MapC.md new file mode 100644 index 00000000..4698c2c7 --- /dev/null +++ b/Documentation/MapC.md @@ -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. diff --git a/Documentation/MapTypes.md b/Documentation/MapTypes.md new file mode 100644 index 00000000..397635a7 --- /dev/null +++ b/Documentation/MapTypes.md @@ -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. \ No newline at end of file diff --git a/Doxyfile b/Doxyfile index c59be232..c2aad9be 100644 --- a/Doxyfile +++ b/Doxyfile @@ -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 \ diff --git a/base/radiant.game b/base/radiant.game new file mode 100644 index 00000000..d3b95048 --- /dev/null +++ b/base/radiant.game @@ -0,0 +1,26 @@ + + diff --git a/base/radiiant.xml b/base/radiiant.xml new file mode 100644 index 00000000..3c1637ef --- /dev/null +++ b/base/radiiant.xml @@ -0,0 +1,26 @@ + + + +"[RadiantPath]vmap" -v -connect [MonitorAddress] -game platform -fs_basepath "[EnginePath]" -fs_game [GameName] + + + +[vmap] -custinfoparms -threads 4 -samplesize 8 "[MapFile]" +[vmap] -vis -v -fast "[MapFile]" + + + +[vmap] -custinfoparms -threads 4 -samplesize 8 "[MapFile]" +[vmap] -vis -v -fast "[MapFile]" +[vmap] -light -custinfoparms -v -samplesize 8 -fast -threads 4 -samples 4 -shade -shadeangle 60 -patchshadows "[MapFile]" + + + +[vmap] -custinfoparms -threads 4 -samplesize 8 "[MapFile]" +[vmap] -vis "[MapFile]" +[vmap] -light -custinfoparms -samplesize 8 -fast -threads 4 -samples 4 -shade -shadeangle 60 -patchshadows "[MapFile]" + + + + + diff --git a/base/src/client/camera.qc b/base/src/client/camera.qc index 585e7334..ea0c7bcf 100644 --- a/base/src/client/camera.qc +++ b/base/src/client/camera.qc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2022 Vera Visions LLC. + * Copyright (c) 2016-2021 Marco Cawthorne * * 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]; } diff --git a/base/src/client/viewmodel.qc b/base/src/client/viewmodel.qc index 77a1f6f7..f20c5ae7 100644 --- a/base/src/client/viewmodel.qc +++ b/base/src/client/viewmodel.qc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2022 Vera Visions LLC. + * Copyright (c) 2016-2021 Marco Cawthorne * * 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; } diff --git a/base/src/server/gamerules.qc b/base/src/server/gamerules.qc index 3e9b3791..ab2e3fcf 100644 --- a/base/src/server/gamerules.qc +++ b/base/src/server/gamerules.qc @@ -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); diff --git a/base/src/server/gamerules_singleplayer.qc b/base/src/server/gamerules_singleplayer.qc index a7f558ff..b5ce14b4 100644 --- a/base/src/server/gamerules_singleplayer.qc +++ b/base/src/server/gamerules_singleplayer.qc @@ -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]; diff --git a/base/src/shared/include.src b/base/src/shared/include.src index 364f0f1c..7678239c 100644 --- a/base/src/shared/include.src +++ b/base/src/shared/include.src @@ -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 diff --git a/base/src/shared/player.qc b/base/src/shared/player.qc index 432a487f..e5a221c6 100644 --- a/base/src/shared/player.qc +++ b/base/src/shared/player.qc @@ -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 diff --git a/make_mapdef.sh b/make_mapdef.sh index 9b58bf35..45320b0c 100755 --- a/make_mapdef.sh +++ b/make_mapdef.sh @@ -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" diff --git a/platform/base_glsl.pk3dir/glsl/lightmapped.glsl b/platform/base_glsl.pk3dir/glsl/lightmapped.glsl index 84023f3e..b52d1e78 100644 --- a/platform/base_glsl.pk3dir/glsl/lightmapped.glsl +++ b/platform/base_glsl.pk3dir/glsl/lightmapped.glsl @@ -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 diff --git a/platform/base_glsl.pk3dir/glsl/portal.glsl b/platform/base_glsl.pk3dir/glsl/portal.glsl new file mode 100644 index 00000000..d6a5ec44 --- /dev/null +++ b/platform/base_glsl.pk3dir/glsl/portal.glsl @@ -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 diff --git a/platform/base_scripts.pk3dir/def/bot.def b/platform/base_scripts.pk3dir/def/bot.def index 6ff536ca..5c17aa14 100644 --- a/platform/base_scripts.pk3dir/def/bot.def +++ b/platform/base_scripts.pk3dir/def/bot.def @@ -1,4 +1,4 @@ entityDef bot { - spawnclass NSBot + "spawnclass" "NSBot" } \ No newline at end of file diff --git a/platform/base_scripts.pk3dir/def/player.def b/platform/base_scripts.pk3dir/def/player.def new file mode 100644 index 00000000..d32cb70c --- /dev/null +++ b/platform/base_scripts.pk3dir/def/player.def @@ -0,0 +1,4 @@ +entityDef player +{ + "spawnclass" "NSClientPlayer" +} \ No newline at end of file diff --git a/platform/base_scripts.pk3dir/def/spawns.def b/platform/base_scripts.pk3dir/def/spawns.def index 50c9e671..c3fe07c4 100644 --- a/platform/base_scripts.pk3dir/def/spawns.def +++ b/platform/base_scripts.pk3dir/def/spawns.def @@ -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" } \ No newline at end of file diff --git a/platform/platform_default.cfg b/platform/platform_default.cfg index cec2908b..955990b9 100644 --- a/platform/platform_default.cfg +++ b/platform/platform_default.cfg @@ -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 diff --git a/src/botlib/NSBot.h b/src/botlib/NSBot.h index af6884d1..180b7d6a 100644 --- a/src/botlib/NSBot.h +++ b/src/botlib/NSBot.h @@ -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)); diff --git a/src/botlib/NSBot.qc b/src/botlib/NSBot.qc index 52d99979..74f12d7b 100644 --- a/src/botlib/NSBot.qc +++ b/src/botlib/NSBot.qc @@ -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 diff --git a/src/botlib/bot_chat.qc b/src/botlib/chat.qc similarity index 100% rename from src/botlib/bot_chat.qc rename to src/botlib/chat.qc diff --git a/src/botlib/bot_combat.qc b/src/botlib/combat.qc similarity index 94% rename from src/botlib/bot_combat.qc rename to src/botlib/combat.qc index df03cfc7..3495486b 100644 --- a/src/botlib/bot_combat.qc +++ b/src/botlib/combat.qc @@ -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; diff --git a/src/botlib/cvars.h b/src/botlib/cvars.h new file mode 100644 index 00000000..6a29ccc7 --- /dev/null +++ b/src/botlib/cvars.h @@ -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; \ No newline at end of file diff --git a/src/botlib/defs.h b/src/botlib/defs.h index 30556043..db5668f2 100644 --- a/src/botlib/defs.h +++ b/src/botlib/defs.h @@ -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 diff --git a/src/botlib/entities.qc b/src/botlib/entities.qc new file mode 100644 index 00000000..e69de29b diff --git a/src/botlib/include.src b/src/botlib/include.src index e6ee6691..ce661035 100644 --- a/src/botlib/include.src +++ b/src/botlib/include.src @@ -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 diff --git a/src/botlib/route.qc b/src/botlib/route.qc index 28eb94d8..2b3a92dd 100644 --- a/src/botlib/route.qc +++ b/src/botlib/route.qc @@ -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); diff --git a/src/client/NSView.qc b/src/client/NSView.qc index d1fead87..a9777b7e 100644 --- a/src/client/NSView.qc +++ b/src/client/NSView.qc @@ -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; } } diff --git a/src/client/cmd.qc b/src/client/cmd.qc index 60138c3c..0fdd14e9 100644 --- a/src/client/cmd.qc +++ b/src/client/cmd.qc @@ -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"); diff --git a/src/client/defs.h b/src/client/defs.h index 3e7583b0..4fa5fe4a 100644 --- a/src/client/defs.h +++ b/src/client/defs.h @@ -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; diff --git a/src/client/efx.qc b/src/client/efx.qc index 6c33aa9d..e4e572a0 100644 --- a/src/client/efx.qc +++ b/src/client/efx.qc @@ -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 diff --git a/src/client/entities.qc b/src/client/entities.qc index 8fdcb76c..0ad2d1de 100644 --- a/src/client/entities.qc +++ b/src/client/entities.qc @@ -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; diff --git a/src/client/entry.qc b/src/client/entry.qc index b2db52ac..7c38851a 100644 --- a/src/client/entry.qc +++ b/src/client/entry.qc @@ -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); } diff --git a/src/client/event.qc b/src/client/event.qc index 98f08006..ddb11e74 100644 --- a/src/client/event.qc +++ b/src/client/event.qc @@ -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 diff --git a/src/client/view.qc b/src/client/view.qc index b423f56e..9ffd455e 100644 --- a/src/client/view.qc +++ b/src/client/view.qc @@ -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; } diff --git a/src/gs-entbase/client/func_smokevolume.qc b/src/gs-entbase/client/func_smokevolume.qc index cc7e37e2..fa3a58e4 100644 --- a/src/gs-entbase/client/func_smokevolume.qc +++ b/src/gs-entbase/client/func_smokevolume.qc @@ -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); diff --git a/src/gs-entbase/server.src b/src/gs-entbase/server.src index d2ddd019..7563a455 100644 --- a/src/gs-entbase/server.src +++ b/src/gs-entbase/server.src @@ -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 diff --git a/src/gs-entbase/server/func_button.qc b/src/gs-entbase/server/func_button.qc index ccd1c07d..c66d5473 100644 --- a/src/gs-entbase/server/func_button.qc +++ b/src/gs-entbase/server/func_button.qc @@ -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); } -} \ No newline at end of file +} diff --git a/src/gs-entbase/server/func_door.qc b/src/gs-entbase/server/func_door.qc index 24a8590b..5e0c1350 100644 --- a/src/gs-entbase/server/func_door.qc +++ b/src/gs-entbase/server/func_door.qc @@ -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); } diff --git a/src/gs-entbase/server/func_door_rotating.qc b/src/gs-entbase/server/func_door_rotating.qc index 4658024f..2308ae6b 100644 --- a/src/gs-entbase/server/func_door_rotating.qc +++ b/src/gs-entbase/server/func_door_rotating.qc @@ -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); } diff --git a/src/gs-entbase/server/func_healthcharger.qc b/src/gs-entbase/server/func_healthcharger.qc index 9f70fab8..7d5ec381 100644 --- a/src/gs-entbase/server/func_healthcharger.qc +++ b/src/gs-entbase/server/func_healthcharger.qc @@ -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(); diff --git a/src/gs-entbase/server/func_recharge.qc b/src/gs-entbase/server/func_recharge.qc index 5ca9bcc9..32a0dab7 100644 --- a/src/gs-entbase/server/func_recharge.qc +++ b/src/gs-entbase/server/func_recharge.qc @@ -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; } diff --git a/src/gs-entbase/server/func_rot_button.qc b/src/gs-entbase/server/func_rot_button.qc index 39c66bee..d5dcc550 100644 --- a/src/gs-entbase/server/func_rot_button.qc +++ b/src/gs-entbase/server/func_rot_button.qc @@ -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(); diff --git a/src/gs-entbase/server/func_tracktrain.qc b/src/gs-entbase/server/func_tracktrain.qc index 97e6777b..25d88b4c 100644 --- a/src/gs-entbase/server/func_tracktrain.qc +++ b/src/gs-entbase/server/func_tracktrain.qc @@ -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) diff --git a/src/gs-entbase/server/monster_generic.qc b/src/gs-entbase/server/monster_generic.qc index ac419aa2..ea264d69 100644 --- a/src/gs-entbase/server/monster_generic.qc +++ b/src/gs-entbase/server/monster_generic.qc @@ -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); } } diff --git a/src/gs-entbase/server/point_trigger.qc b/src/gs-entbase/server/point_trigger.qc index 950de135..087ea691 100644 --- a/src/gs-entbase/server/point_trigger.qc +++ b/src/gs-entbase/server/point_trigger.qc @@ -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; diff --git a/src/gs-entbase/server/script_brushmodel.qc b/src/gs-entbase/server/script_brushmodel.qc new file mode 100644 index 00000000..e1d6f7d3 --- /dev/null +++ b/src/gs-entbase/server/script_brushmodel.qc @@ -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) +{ + +} + diff --git a/src/gs-entbase/server/script_model.qc b/src/gs-entbase/server/script_model.qc new file mode 100644 index 00000000..500b4f15 --- /dev/null +++ b/src/gs-entbase/server/script_model.qc @@ -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) +{ + +} + + diff --git a/src/gs-entbase/server/script_origin.qc b/src/gs-entbase/server/script_origin.qc new file mode 100644 index 00000000..513ca8ad --- /dev/null +++ b/src/gs-entbase/server/script_origin.qc @@ -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) +{ + +} + diff --git a/src/gs-entbase/server/script_struct.qc b/src/gs-entbase/server/script_struct.qc new file mode 100644 index 00000000..b500c0a2 --- /dev/null +++ b/src/gs-entbase/server/script_struct.qc @@ -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) +{ + +} + diff --git a/src/gs-entbase/server/script_vehicle.qc b/src/gs-entbase/server/script_vehicle.qc new file mode 100644 index 00000000..f172b6dc --- /dev/null +++ b/src/gs-entbase/server/script_vehicle.qc @@ -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) +{ + +} + diff --git a/src/gs-entbase/server/trigger_hurt.qc b/src/gs-entbase/server/trigger_hurt.qc index 882020a0..dc0351d9 100644 --- a/src/gs-entbase/server/trigger_hurt.qc +++ b/src/gs-entbase/server/trigger_hurt.qc @@ -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); } } diff --git a/src/gs-entbase/server/trigger_multiple.qc b/src/gs-entbase/server/trigger_multiple.qc index bb1883e9..24bb7748 100644 --- a/src/gs-entbase/server/trigger_multiple.qc +++ b/src/gs-entbase/server/trigger_multiple.qc @@ -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) diff --git a/src/gs-entbase/server/trigger_playerfreeze.qc b/src/gs-entbase/server/trigger_playerfreeze.qc index 2ff39201..6eafa4fb 100644 --- a/src/gs-entbase/server/trigger_playerfreeze.qc +++ b/src/gs-entbase/server/trigger_playerfreeze.qc @@ -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; } } diff --git a/src/gs-entbase/server/trigger_teleport.qc b/src/gs-entbase/server/trigger_teleport.qc index 4371d88d..3059c1fa 100644 --- a/src/gs-entbase/server/trigger_teleport.qc +++ b/src/gs-entbase/server/trigger_teleport.qc @@ -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); diff --git a/src/gs-entbase/shared/ambient_generic.qc b/src/gs-entbase/shared/ambient_generic.qc index d01886fa..363ab1ec 100644 --- a/src/gs-entbase/shared/ambient_generic.qc +++ b/src/gs-entbase/shared/ambient_generic.qc @@ -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 { diff --git a/src/gs-entbase/shared/env_beam.qc b/src/gs-entbase/shared/env_beam.qc index 041ac74a..31b42f87 100644 --- a/src/gs-entbase/shared/env_beam.qc +++ b/src/gs-entbase/shared/env_beam.qc @@ -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' */ diff --git a/src/gs-entbase/shared/env_fog_controller.qc b/src/gs-entbase/shared/env_fog_controller.qc index 0fcbe966..e7cea85f 100644 --- a/src/gs-entbase/shared/env_fog_controller.qc +++ b/src/gs-entbase/shared/env_fog_controller.qc @@ -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)); diff --git a/src/gs-entbase/shared/env_funnel.qc b/src/gs-entbase/shared/env_funnel.qc index 97de5f70..030ffbf1 100644 --- a/src/gs-entbase/shared/env_funnel.qc +++ b/src/gs-entbase/shared/env_funnel.qc @@ -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); } diff --git a/src/gs-entbase/shared/env_instructor_hint.qc b/src/gs-entbase/shared/env_instructor_hint.qc index 4a329f07..dc7b6682 100644 --- a/src/gs-entbase/shared/env_instructor_hint.qc +++ b/src/gs-entbase/shared/env_instructor_hint.qc @@ -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 */ diff --git a/src/gs-entbase/shared/env_laser.qc b/src/gs-entbase/shared/env_laser.qc index 5463dac7..1ba66157 100644 --- a/src/gs-entbase/shared/env_laser.qc +++ b/src/gs-entbase/shared/env_laser.qc @@ -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)); diff --git a/src/gs-entbase/shared/env_projectedtexture.qc b/src/gs-entbase/shared/env_projectedtexture.qc index 102a6fa2..7f94f80c 100644 --- a/src/gs-entbase/shared/env_projectedtexture.qc +++ b/src/gs-entbase/shared/env_projectedtexture.qc @@ -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) diff --git a/src/gs-entbase/shared/env_sprite.qc b/src/gs-entbase/shared/env_sprite.qc index 315e1c4b..4ad4c88d 100644 --- a/src/gs-entbase/shared/env_sprite.qc +++ b/src/gs-entbase/shared/env_sprite.qc @@ -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). diff --git a/src/gs-entbase/shared/env_steam.qc b/src/gs-entbase/shared/env_steam.qc index 5c7f575e..14b83991 100644 --- a/src/gs-entbase/shared/env_steam.qc +++ b/src/gs-entbase/shared/env_steam.qc @@ -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); } diff --git a/src/gs-entbase/shared/func_tankmortar.qc b/src/gs-entbase/shared/func_tankmortar.qc index 388ebdfc..a692a4a0 100644 --- a/src/gs-entbase/shared/func_tankmortar.qc +++ b/src/gs-entbase/shared/func_tankmortar.qc @@ -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(); } diff --git a/src/gs-entbase/shared/func_vehicle.qc b/src/gs-entbase/shared/func_vehicle.qc index bf32caea..42378fab 100644 --- a/src/gs-entbase/shared/func_vehicle.qc +++ b/src/gs-entbase/shared/func_vehicle.qc @@ -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; diff --git a/src/gs-entbase/shared/phys_rope.qc b/src/gs-entbase/shared/phys_rope.qc index ffb2ef4d..5a8259c1 100644 --- a/src/gs-entbase/shared/phys_rope.qc +++ b/src/gs-entbase/shared/phys_rope.qc @@ -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": diff --git a/src/gs-entbase/shared/prop_rope.qc b/src/gs-entbase/shared/prop_rope.qc index 0dc3bde4..6030baf7 100644 --- a/src/gs-entbase/shared/prop_rope.qc +++ b/src/gs-entbase/shared/prop_rope.qc @@ -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) diff --git a/src/gs-entbase/shared/prop_vehicle_driveable.qc b/src/gs-entbase/shared/prop_vehicle_driveable.qc index 22a176e2..cfbfc4ae 100644 --- a/src/gs-entbase/shared/prop_vehicle_driveable.qc +++ b/src/gs-entbase/shared/prop_vehicle_driveable.qc @@ -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)) diff --git a/src/gs-entbase/shared/trigger_camera.qc b/src/gs-entbase/shared/trigger_camera.qc index 1f941900..32205733 100644 --- a/src/gs-entbase/shared/trigger_camera.qc +++ b/src/gs-entbase/shared/trigger_camera.qc @@ -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)); } diff --git a/src/gs-entbase/shared/trigger_push.qc b/src/gs-entbase/shared/trigger_push.qc index 72a07986..992733c1 100644 --- a/src/gs-entbase/shared/trigger_push.qc +++ b/src/gs-entbase/shared/trigger_push.qc @@ -337,7 +337,7 @@ void trigger_push::Touch(entity eToucher) { #ifdef SERVER - eActivator = eToucher; + eActivator = (NSEntity)eToucher; #endif switch(eToucher.movetype) { diff --git a/src/gs-entbase/shared/worldspawn.qc b/src/gs-entbase/shared/worldspawn.qc index b1753d3c..f5591cfb 100644 --- a/src/gs-entbase/shared/worldspawn.qc +++ b/src/gs-entbase/shared/worldspawn.qc @@ -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 diff --git a/src/menu-fn/includes.src b/src/menu-fn/includes.src index e7d0c0ed..8f68e233 100644 --- a/src/menu-fn/includes.src +++ b/src/menu-fn/includes.src @@ -1,7 +1,6 @@ #includelist ../shared/fteextensions.qc ../shared/math.h -../shared/math.qc ../shared/global.h ../shared/platform.h ../platform/defs.h diff --git a/src/menu-fn/m_customize.qc b/src/menu-fn/m_customize.qc index ae7be7f4..2f2588f7 100644 --- a/src/menu-fn/m_customize.qc +++ b/src/menu-fn/m_customize.qc @@ -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; } } diff --git a/src/platform/util.qc b/src/platform/util.qc index 16b841b0..cca76fce 100644 --- a/src/platform/util.qc +++ b/src/platform/util.qc @@ -55,10 +55,4 @@ Util_CmdToKey(string cmd) } return sBindTx; -} - -float -lerp(float fA, float fB, float fPercent) -{ - return (fA * (1 - fPercent)) + (fB * fPercent); -} +} \ No newline at end of file diff --git a/src/server/NSGameRules.qc b/src/server/NSGameRules.qc index 1a874a7a..c4027c0f 100644 --- a/src/server/NSGameRules.qc +++ b/src/server/NSGameRules.qc @@ -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"); diff --git a/src/server/cmd_cl.qc b/src/server/cmd_cl.qc new file mode 100644 index 00000000..bc1060e6 --- /dev/null +++ b/src/server/cmd_cl.qc @@ -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); + } +} \ No newline at end of file diff --git a/src/server/cmd_sv.qc b/src/server/cmd_sv.qc new file mode 100644 index 00000000..6547fbde --- /dev/null +++ b/src/server/cmd_sv.qc @@ -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); +} \ No newline at end of file diff --git a/src/server/defs.h b/src/server/defs.h index 7aa8f227..c9d48060 100644 --- a/src/server/defs.h +++ b/src/server/defs.h @@ -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); diff --git a/src/server/entityDef.qc b/src/server/entityDef.qc index cbc09cd4..49cdeaaa 100644 --- a/src/server/entityDef.qc +++ b/src/server/entityDef.qc @@ -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; -} \ No newline at end of file +} + +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))); + } + } +} diff --git a/src/server/entry.qc b/src/server/entry.qc index eba0d5e1..1b77d7ca 100644 --- a/src/server/entry.qc +++ b/src/server/entry.qc @@ -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 diff --git a/src/server/include.src b/src/server/include.src index 7a11d9e1..e6e0a21a 100644 --- a/src/server/include.src +++ b/src/server/include.src @@ -15,5 +15,8 @@ modelevent.qc mapcycle.qc entityDef.qc maptweaks.qc +scripts.qc +cmd_cl.qc +cmd_sv.qc entry.qc #endlist diff --git a/src/server/lament.qc b/src/server/lament.qc index 12a2477e..a7f5f678 100644 --- a/src/server/lament.qc +++ b/src/server/lament.qc @@ -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; diff --git a/src/server/mapC.h b/src/server/mapC.h new file mode 100644 index 00000000..2b9406d6 --- /dev/null +++ b/src/server/mapC.h @@ -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); +} diff --git a/src/server/nodes.qc b/src/server/nodes.qc index 9a5357bd..c950a728 100644 --- a/src/server/nodes.qc +++ b/src/server/nodes.qc @@ -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 diff --git a/src/server/scripts.qc b/src/server/scripts.qc new file mode 100644 index 00000000..f7803157 --- /dev/null +++ b/src/server/scripts.qc @@ -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; +} diff --git a/src/server/weapons.qc b/src/server/weapons.qc index 9fc7468c..f804ab9b 100644 --- a/src/server/weapons.qc +++ b/src/server/weapons.qc @@ -382,4 +382,15 @@ CSEv_DropWeapon(void) player pl = (player)self; Weapon_DropCurrentWeapon(pl); } -#endif \ No newline at end of file +#endif + +void +CSEv_PlayerSwitchWeapon_i(int w) +{ + player pl = (player)self; + + if (pl.activeweapon != w) { + pl.activeweapon = w; + Weapons_Draw(pl); + } +} \ No newline at end of file diff --git a/src/shared/NSClient.h b/src/shared/NSClient.h index 4e594095..ab14d174 100644 --- a/src/shared/NSClient.h +++ b/src/shared/NSClient.h @@ -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. */ diff --git a/src/shared/NSClient.qc b/src/shared/NSClient.qc index 1198fd5d..965dca8e 100644 --- a/src/shared/NSClient.qc +++ b/src/shared/NSClient.qc @@ -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) diff --git a/src/shared/NSClientPlayer.h b/src/shared/NSClientPlayer.h index 8c75f5b7..fa6ba9ef 100644 --- a/src/shared/NSClientPlayer.h +++ b/src/shared/NSClientPlayer.h @@ -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 diff --git a/src/shared/NSClientPlayer.qc b/src/shared/NSClientPlayer.qc index cfb177eb..5c3bcf3b 100644 --- a/src/shared/NSClientPlayer.qc +++ b/src/shared/NSClientPlayer.qc @@ -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; } diff --git a/src/shared/NSClientSpectator.qc b/src/shared/NSClientSpectator.qc index 629a231b..811e2b72 100644 --- a/src/shared/NSClientSpectator.qc +++ b/src/shared/NSClientSpectator.qc @@ -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 diff --git a/src/shared/NSEntity.h b/src/shared/NSEntity.h index 6402abf6..5cdf3726 100644 --- a/src/shared/NSEntity.h +++ b/src/shared/NSEntity.h @@ -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); diff --git a/src/shared/NSEntity.qc b/src/shared/NSEntity.qc index ed2e4f10..484028dc 100644 --- a/src/shared/NSEntity.qc +++ b/src/shared/NSEntity.qc @@ -14,7 +14,9 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -static bool droptofloorwrapper( entity foo ) { +static bool +droptofloorwrapper(entity foo) +{ bool result; entity old_self = self; self = foo; @@ -23,168 +25,200 @@ static bool droptofloorwrapper( entity foo ) { return result; } -void NSEntity::NSEntity( void ) { +void +NSEntity::NSEntity(void) +{ identity = 1; m_flSpawnTime = time; + m_vecEditorColor = [1,1,1]; } -void NSEntity::Spawned( void ) { +void +NSEntity::Spawned(void) +{ super::Spawned(); m_oldAngle = angles; m_oldOrigin = origin; - m_oldModel = Util_FixModel( model ); + m_oldModel = Util_FixModel(model); m_oldSolid = solid; #ifdef SERVER m_oldstrTarget = target; - if ( m_oldModel && m_oldModel != "" ) { - precache_model( GetSpawnModel() ); + if (m_oldModel && m_oldModel != "") { + precache_model(GetSpawnModel()); } - if ( m_strOnTrigger ) { - m_strOnTrigger = CreateOutput( m_strOnTrigger ); + if (m_strOnTrigger) { + m_strOnTrigger = CreateOutput(m_strOnTrigger); } #endif } -float NSEntity::EntIndex( void ) { - return ( num_for_edict( this ) ); +float +NSEntity::EntIndex(void) +{ + return (num_for_edict(this)); } -bool NSEntity::DropToFloor( void ) { - return droptofloorwrapper( this ); +bool +NSEntity::DropToFloor(void) +{ + return droptofloorwrapper(this); } -vector NSEntity::GetForward( void ) { - makevectors( angles ); - return ( v_forward ); +vector +NSEntity::GetForward(void) +{ + return anglesToForward(angles); } -vector NSEntity::GetRight( void ) { - makevectors( angles ); - return ( v_right ); +vector +NSEntity::GetRight(void) +{ + return anglesToRight(angles); } -vector NSEntity::GetUp( void ) { - makevectors( angles ); - return ( v_up ); +vector +NSEntity::GetUp(void) +{ + return anglesToUp(angles); } -vector NSEntity::WorldSpaceCenter( void ) { - return ( absmin + ( 0.5 * ( absmax - absmin ) ) ); +vector +NSEntity::WorldSpaceCenter(void) +{ + return (absmin + (0.5 * (absmax - absmin))); } -float NSEntity::WaterLevel( void ) { - return ( waterlevel ); +float +NSEntity::WaterLevel(void) +{ + return (waterlevel); } -bool NSEntity::VisibleVec( vector org ) { +bool +NSEntity::VisibleVec(vector org) +{ vector flDelta; float flFoV; - makevectors( angles ); - flDelta = normalize( org - origin ); - flFoV = flDelta * v_forward; + flDelta = vectorNormalize(org - origin); + flFoV = flDelta * GetForward(); - if ( flFoV > 0.3f ) { - traceline( origin, org, TRUE, this ); - if ( trace_fraction == 1.0f ) { - return ( true ); + if (flFoV > 0.3f) { + traceline(origin, org, TRUE, this); + if (trace_fraction == 1.0f) { + return (true); } } - return ( false ); + return (false); } -bool NSEntity::Visible( entity ent ) { +bool +NSEntity::Visible(entity ent) +{ /* is it in our field of view? */ - if ( DistanceFromYaw(ent.origin) > 0.3f ) { - traceline( origin, ent.origin, MOVE_NORMAL, this ); - if ( trace_fraction == 1.0f || trace_ent == ent ) { - print( sprintf( "%s can see %s\n", classname, ent.classname ) ); - return ( true ); + if (DistanceFromYaw(ent.origin) > 0.3f) { + traceline(origin, ent.origin, MOVE_NORMAL, this); + + if (trace_fraction == 1.0f || trace_ent == ent) { + print(sprintf("%s can see %s\n", classname, ent.classname)); + return (true); } } - print( sprintf( "%s can not see %s\n", classname, ent.classname ) ); - return ( false ); + + print(sprintf("%s can not see %s\n", classname, ent.classname)); + return (false); } -float NSEntity::DistanceFromYaw( vector targetPos ) { - vector vecDelta; - makevectors( angles ); - vecDelta = normalize( targetPos - origin ); - return vecDelta * v_forward; +float +NSEntity::DistanceFromYaw(vector targetPos) +{ + return vectorNormalize(targetPos - origin) * GetForward(); } -bool NSEntity::HasSpawnFlags( float sf ) { - return ( spawnflags & sf ) ? true : false; +bool +NSEntity::HasSpawnFlags(float sf) +{ + return (spawnflags & sf) ? (true) : (false); } -bool NSEntity::IsOnGround( void ) { - return ( flags & FL_ONGROUND ) ? true : false; +bool +NSEntity::IsOnGround(void) +{ + return (flags & FL_ONGROUND) ? (true) : (false); } -bool NSEntity::IsSolid( void ) { - return ( solid != SOLID_NOT ) ? true : false; +bool +NSEntity::IsSolid(void) +{ + return (solid != SOLID_NOT) ? (true) : (false); } -entity NSEntity::GetGroundEntity( void ) { - return ( groundentity ); +entity +NSEntity::GetGroundEntity(void) +{ + return (groundentity); } -bool NSEntity::CreatedByMap( void ) { - return ( _mapspawned ); +bool +NSEntity::CreatedByMap(void) +{ + return (_mapspawned); } - - #ifdef CLIENT -void NSEntity::RendererRestarted( void ) { +void +NSEntity::RendererRestarted(void) +{ } -void NSEntity::ReceiveEntity( float flNew, float flChanged ) { - READENTITY_COORD( origin[0], BASEFL_CHANGED_ORIGIN_X ) - READENTITY_COORD( origin[1], BASEFL_CHANGED_ORIGIN_Y ) - READENTITY_COORD( origin[2], BASEFL_CHANGED_ORIGIN_Z ) - READENTITY_ANGLE( angles[0], BASEFL_CHANGED_ANGLES_X ) - READENTITY_ANGLE( angles[1], BASEFL_CHANGED_ANGLES_Y ) - READENTITY_ANGLE( angles[2], BASEFL_CHANGED_ANGLES_Z ) - READENTITY_SHORT( modelindex, BASEFL_CHANGED_MODELINDEX ) - READENTITY_BYTE( solid, BASEFL_CHANGED_SOLID ) - READENTITY_BYTE( movetype, BASEFL_CHANGED_FLAGS ) - READENTITY_INT( flags, BASEFL_CHANGED_FLAGS ) - READENTITY_COORD( mins[0], BASEFL_CHANGED_SIZE ) - READENTITY_COORD( mins[1], BASEFL_CHANGED_SIZE ) - READENTITY_COORD( mins[2], BASEFL_CHANGED_SIZE ) - READENTITY_COORD( maxs[0], BASEFL_CHANGED_SIZE ) - READENTITY_COORD( maxs[1], BASEFL_CHANGED_SIZE ) - READENTITY_COORD( maxs[2], BASEFL_CHANGED_SIZE ) - READENTITY_BYTE( frame, BASEFL_CHANGED_FRAME ) - READENTITY_FLOAT( skin, BASEFL_CHANGED_SKIN ) - READENTITY_FLOAT( effects, BASEFL_CHANGED_EFFECTS ) - READENTITY_FLOAT( scale, BASEFL_CHANGED_SCALE ) - READENTITY_COORD( velocity[0], BASEFL_CHANGED_VELOCITY_X ) - READENTITY_COORD( velocity[1], BASEFL_CHANGED_VELOCITY_Y ) - READENTITY_COORD( velocity[2], BASEFL_CHANGED_VELOCITY_Z ) - READENTITY_COORD( avelocity[0], BASEFL_CHANGED_ANGULARVELOCITY ) - READENTITY_COORD( avelocity[1], BASEFL_CHANGED_ANGULARVELOCITY ) - READENTITY_COORD( avelocity[2], BASEFL_CHANGED_ANGULARVELOCITY ) - if ( modelindex ) { - drawmask = MASK_ENGINE; - } else { - drawmask = 0; - } +void +NSEntity::ReceiveEntity(float flNew, float flChanged) +{ + READENTITY_COORD(origin[0], BASEFL_CHANGED_ORIGIN_X) + READENTITY_COORD(origin[1], BASEFL_CHANGED_ORIGIN_Y) + READENTITY_COORD(origin[2], BASEFL_CHANGED_ORIGIN_Z) + READENTITY_ANGLE(angles[0], BASEFL_CHANGED_ANGLES_X) + READENTITY_ANGLE(angles[1], BASEFL_CHANGED_ANGLES_Y) + READENTITY_ANGLE(angles[2], BASEFL_CHANGED_ANGLES_Z) + READENTITY_SHORT(modelindex, BASEFL_CHANGED_MODELINDEX) + READENTITY_BYTE(solid, BASEFL_CHANGED_SOLID) + READENTITY_BYTE(movetype, BASEFL_CHANGED_FLAGS) + READENTITY_INT(flags, BASEFL_CHANGED_FLAGS) + READENTITY_INT(vv_flags, BASEFL_CHANGED_FLAGS) + READENTITY_COORD(mins[0], BASEFL_CHANGED_SIZE) + READENTITY_COORD(mins[1], BASEFL_CHANGED_SIZE) + READENTITY_COORD(mins[2], BASEFL_CHANGED_SIZE) + READENTITY_COORD(maxs[0], BASEFL_CHANGED_SIZE) + READENTITY_COORD(maxs[1], BASEFL_CHANGED_SIZE) + READENTITY_COORD(maxs[2], BASEFL_CHANGED_SIZE) + READENTITY_BYTE(frame, BASEFL_CHANGED_FRAME) + READENTITY_FLOAT(skin, BASEFL_CHANGED_SKIN) + READENTITY_FLOAT(effects, BASEFL_CHANGED_EFFECTS) + READENTITY_FLOAT(scale, BASEFL_CHANGED_SCALE) + READENTITY_COORD(velocity[0], BASEFL_CHANGED_VELOCITY_X) + READENTITY_COORD(velocity[1], BASEFL_CHANGED_VELOCITY_Y) + READENTITY_COORD(velocity[2], BASEFL_CHANGED_VELOCITY_Z) + READENTITY_COORD(avelocity[0], BASEFL_CHANGED_ANGULARVELOCITY) + READENTITY_COORD(avelocity[1], BASEFL_CHANGED_ANGULARVELOCITY) + READENTITY_COORD(avelocity[2], BASEFL_CHANGED_ANGULARVELOCITY) - if ( scale == 0.0f ) + drawmask = (modelindex != 0) ? MASK_ENGINE : 0; + + if (scale == 0.0f) scale = 1.0f; - if ( flChanged & BASEFL_CHANGED_SIZE ) - setsize( this, mins, maxs ); + if (flChanged & BASEFL_CHANGED_SIZE) + setsize(this, mins, maxs); } -void NSEntity::postdraw( void ) { +void +NSEntity::postdraw(void) +{ } @@ -192,21 +226,23 @@ void NSEntity::postdraw( void ) { void NSEntity::DebugDraw(void) { - + DebugBox(GetOrigin(), GetMins(), GetMaxs(), m_vecEditorColor, 0.75f); } /* Make sure StartFrame calls this */ -float NSEntity::SendEntity( entity ePEnt, float flChanged ) { - if ( !modelindex ) - return ( 0 ); +float +NSEntity::SendEntity(entity ePEnt, float flChanged) +{ + if (!modelindex) + return (0); - if ( clienttype( ePEnt ) != CLIENTTYPE_REAL ) - return ( 0 ); + if (clienttype(ePEnt) != CLIENTTYPE_REAL) + return (0); - if ( alpha == 0.0f ) - return ( 0 ); + if (alpha == 0.0f) + return (0); - WriteByte( MSG_ENTITY, ENT_ENTITY ); + WriteByte(MSG_ENTITY, ENT_ENTITY); /* optimisation */ { @@ -225,133 +261,154 @@ float NSEntity::SendEntity( entity ePEnt, float flChanged ) { } /* broadcast how much data is expected to be read */ - WriteFloat( MSG_ENTITY, flChanged ); + WriteFloat(MSG_ENTITY, flChanged); - SENDENTITY_COORD( origin[0], BASEFL_CHANGED_ORIGIN_X ) - SENDENTITY_COORD( origin[1], BASEFL_CHANGED_ORIGIN_Y ) - SENDENTITY_COORD( origin[2], BASEFL_CHANGED_ORIGIN_Z ) - SENDENTITY_ANGLE( angles[0], BASEFL_CHANGED_ANGLES_X ) - SENDENTITY_ANGLE( angles[1], BASEFL_CHANGED_ANGLES_Y ) - SENDENTITY_ANGLE( angles[2], BASEFL_CHANGED_ANGLES_Z ) - SENDENTITY_SHORT( modelindex, BASEFL_CHANGED_MODELINDEX ) - SENDENTITY_BYTE( solid, BASEFL_CHANGED_SOLID ) - SENDENTITY_BYTE( movetype, BASEFL_CHANGED_FLAGS ) - SENDENTITY_INT( flags, BASEFL_CHANGED_FLAGS ) - SENDENTITY_COORD( mins[0], BASEFL_CHANGED_SIZE ) - SENDENTITY_COORD( mins[1], BASEFL_CHANGED_SIZE ) - SENDENTITY_COORD( mins[2], BASEFL_CHANGED_SIZE ) - SENDENTITY_COORD( maxs[0], BASEFL_CHANGED_SIZE ) - SENDENTITY_COORD( maxs[1], BASEFL_CHANGED_SIZE ) - SENDENTITY_COORD( maxs[2], BASEFL_CHANGED_SIZE ) - SENDENTITY_BYTE( frame, BASEFL_CHANGED_FRAME ) - SENDENTITY_FLOAT( skin, BASEFL_CHANGED_SKIN ) - SENDENTITY_FLOAT( effects, BASEFL_CHANGED_EFFECTS ) - SENDENTITY_FLOAT( scale, BASEFL_CHANGED_SCALE ) - SENDENTITY_COORD( velocity[0], BASEFL_CHANGED_VELOCITY_X ) - SENDENTITY_COORD( velocity[1], BASEFL_CHANGED_VELOCITY_Y ) - SENDENTITY_COORD( velocity[2], BASEFL_CHANGED_VELOCITY_Z ) - SENDENTITY_COORD( avelocity[0], BASEFL_CHANGED_ANGULARVELOCITY ) - SENDENTITY_COORD( avelocity[1], BASEFL_CHANGED_ANGULARVELOCITY ) - SENDENTITY_COORD( avelocity[2], BASEFL_CHANGED_ANGULARVELOCITY ) - return ( 1 ); + SENDENTITY_COORD(origin[0], BASEFL_CHANGED_ORIGIN_X) + SENDENTITY_COORD(origin[1], BASEFL_CHANGED_ORIGIN_Y) + SENDENTITY_COORD(origin[2], BASEFL_CHANGED_ORIGIN_Z) + SENDENTITY_ANGLE(angles[0], BASEFL_CHANGED_ANGLES_X) + SENDENTITY_ANGLE(angles[1], BASEFL_CHANGED_ANGLES_Y) + SENDENTITY_ANGLE(angles[2], BASEFL_CHANGED_ANGLES_Z) + SENDENTITY_SHORT(modelindex, BASEFL_CHANGED_MODELINDEX) + SENDENTITY_BYTE(solid, BASEFL_CHANGED_SOLID) + SENDENTITY_BYTE(movetype, BASEFL_CHANGED_FLAGS) + SENDENTITY_INT(flags, BASEFL_CHANGED_FLAGS) + SENDENTITY_INT(vv_flags, BASEFL_CHANGED_FLAGS) + SENDENTITY_COORD(mins[0], BASEFL_CHANGED_SIZE) + SENDENTITY_COORD(mins[1], BASEFL_CHANGED_SIZE) + SENDENTITY_COORD(mins[2], BASEFL_CHANGED_SIZE) + SENDENTITY_COORD(maxs[0], BASEFL_CHANGED_SIZE) + SENDENTITY_COORD(maxs[1], BASEFL_CHANGED_SIZE) + SENDENTITY_COORD(maxs[2], BASEFL_CHANGED_SIZE) + SENDENTITY_BYTE(frame, BASEFL_CHANGED_FRAME) + SENDENTITY_FLOAT(skin, BASEFL_CHANGED_SKIN) + SENDENTITY_FLOAT(effects, BASEFL_CHANGED_EFFECTS) + SENDENTITY_FLOAT(scale, BASEFL_CHANGED_SCALE) + SENDENTITY_COORD(velocity[0], BASEFL_CHANGED_VELOCITY_X) + SENDENTITY_COORD(velocity[1], BASEFL_CHANGED_VELOCITY_Y) + SENDENTITY_COORD(velocity[2], BASEFL_CHANGED_VELOCITY_Z) + SENDENTITY_COORD(avelocity[0], BASEFL_CHANGED_ANGULARVELOCITY) + SENDENTITY_COORD(avelocity[1], BASEFL_CHANGED_ANGULARVELOCITY) + SENDENTITY_COORD(avelocity[2], BASEFL_CHANGED_ANGULARVELOCITY) + return (1); } -void NSEntity::EvaluateEntity( void ) { - EVALUATE_VECTOR( origin, 0, BASEFL_CHANGED_ORIGIN_X ) - EVALUATE_VECTOR( origin, 1, BASEFL_CHANGED_ORIGIN_Y ) - EVALUATE_VECTOR( origin, 2, BASEFL_CHANGED_ORIGIN_Z ) - EVALUATE_VECTOR( angles, 0, BASEFL_CHANGED_ANGLES_X ) - EVALUATE_VECTOR( angles, 1, BASEFL_CHANGED_ANGLES_Y ) - EVALUATE_VECTOR( angles, 2, BASEFL_CHANGED_ANGLES_Z ) - EVALUATE_FIELD( modelindex, BASEFL_CHANGED_MODELINDEX ) - EVALUATE_FIELD( solid, BASEFL_CHANGED_SOLID ) - EVALUATE_FIELD( movetype, BASEFL_CHANGED_FLAGS ) - EVALUATE_FIELD( flags, BASEFL_CHANGED_FLAGS ) - EVALUATE_VECTOR( mins, 0, BASEFL_CHANGED_SIZE ) - EVALUATE_VECTOR( mins, 1, BASEFL_CHANGED_SIZE ) - EVALUATE_VECTOR( mins, 2, BASEFL_CHANGED_SIZE ) - EVALUATE_VECTOR( maxs, 0, BASEFL_CHANGED_SIZE ) - EVALUATE_VECTOR( maxs, 1, BASEFL_CHANGED_SIZE ) - EVALUATE_VECTOR( maxs, 2, BASEFL_CHANGED_SIZE ) - EVALUATE_FIELD( frame, BASEFL_CHANGED_FRAME ) - EVALUATE_FIELD( skin, BASEFL_CHANGED_SKIN ) - EVALUATE_FIELD( effects, BASEFL_CHANGED_EFFECTS ) - EVALUATE_FIELD( scale, BASEFL_CHANGED_SCALE ) - EVALUATE_VECTOR( velocity, 0, BASEFL_CHANGED_VELOCITY_X ) - EVALUATE_VECTOR( velocity, 1, BASEFL_CHANGED_VELOCITY_Y ) - EVALUATE_VECTOR( velocity, 2, BASEFL_CHANGED_VELOCITY_Z ) - EVALUATE_VECTOR( avelocity, 0, BASEFL_CHANGED_ANGULARVELOCITY ) - EVALUATE_VECTOR( avelocity, 1, BASEFL_CHANGED_ANGULARVELOCITY ) - EVALUATE_VECTOR( avelocity, 2, BASEFL_CHANGED_ANGULARVELOCITY ) +void +NSEntity::EvaluateEntity(void) +{ + EVALUATE_VECTOR(origin, 0, BASEFL_CHANGED_ORIGIN_X) + EVALUATE_VECTOR(origin, 1, BASEFL_CHANGED_ORIGIN_Y) + EVALUATE_VECTOR(origin, 2, BASEFL_CHANGED_ORIGIN_Z) + EVALUATE_VECTOR(angles, 0, BASEFL_CHANGED_ANGLES_X) + EVALUATE_VECTOR(angles, 1, BASEFL_CHANGED_ANGLES_Y) + EVALUATE_VECTOR(angles, 2, BASEFL_CHANGED_ANGLES_Z) + EVALUATE_FIELD(modelindex, BASEFL_CHANGED_MODELINDEX) + EVALUATE_FIELD(solid, BASEFL_CHANGED_SOLID) + EVALUATE_FIELD(movetype, BASEFL_CHANGED_FLAGS) + EVALUATE_FIELD(flags, BASEFL_CHANGED_FLAGS) + EVALUATE_FIELD(vv_flags, BASEFL_CHANGED_FLAGS) + EVALUATE_VECTOR(mins, 0, BASEFL_CHANGED_SIZE) + EVALUATE_VECTOR(mins, 1, BASEFL_CHANGED_SIZE) + EVALUATE_VECTOR(mins, 2, BASEFL_CHANGED_SIZE) + EVALUATE_VECTOR(maxs, 0, BASEFL_CHANGED_SIZE) + EVALUATE_VECTOR(maxs, 1, BASEFL_CHANGED_SIZE) + EVALUATE_VECTOR(maxs, 2, BASEFL_CHANGED_SIZE) + EVALUATE_FIELD(frame, BASEFL_CHANGED_FRAME) + EVALUATE_FIELD(skin, BASEFL_CHANGED_SKIN) + EVALUATE_FIELD(effects, BASEFL_CHANGED_EFFECTS) + EVALUATE_FIELD(scale, BASEFL_CHANGED_SCALE) + EVALUATE_VECTOR(velocity, 0, BASEFL_CHANGED_VELOCITY_X) + EVALUATE_VECTOR(velocity, 1, BASEFL_CHANGED_VELOCITY_Y) + EVALUATE_VECTOR(velocity, 2, BASEFL_CHANGED_VELOCITY_Z) + EVALUATE_VECTOR(avelocity, 0, BASEFL_CHANGED_ANGULARVELOCITY) + EVALUATE_VECTOR(avelocity, 1, BASEFL_CHANGED_ANGULARVELOCITY) + EVALUATE_VECTOR(avelocity, 2, BASEFL_CHANGED_ANGULARVELOCITY) } /* Make sure StartFrame calls this */ -void NSEntity::ParentUpdate( void ) { +void +NSEntity::ParentUpdate(void) +{ EvaluateEntity(); frame1time += frametime; - if ( m_parent ) { - NSEntity parent; - entity p = find( world, ::targetname, m_parent ); - - if ( p ) { - if ( !m_parent_attachment ) { - parent = ( NSEntity ) p; - vector ofs = parent.origin - parent.GetSpawnOrigin(); - - SetOrigin( GetSpawnOrigin() + ofs ); - } else if ( m_parent_attachment == "origin" ) { - SetOrigin( p.origin ); - } - } - } - /* handle end-touch */ - if ( m_beingTouched == true ) - if ( m_flTouchTime < GetTime() ) { - EndTouch( m_eTouchLast ); + if (m_beingTouched == true) + if (m_flTouchTime < GetTime()) { + EndTouch(m_eTouchLast); m_beingTouched = false; m_eTouchLast = __NULL__; } } -entity NSEntity::GetParent( void ) { - return ( find( world, ::targetname, m_parent ) ); +entity +NSEntity::GetParent(void) +{ + return tag_entity; } -void NSEntity::SetParent( string name ) { - m_parent = name; +void +NSEntity::SetParent(string name) +{ + tag_entity = find(world, ::targetname, m_parent); } -void NSEntity::SetParentAttachment( string name ) { - m_parent_attachment = name; +void +NSEntity::SetParentAttachment(string name) +{ + if (name != "origin") { + tag_index = gettagindex(tag_entity, name); + } else { + tag_index = 0; + } } -void NSEntity::ClearParent( void ) { - m_parent = __NULL__; - m_parent_attachment = __NULL__; +void +NSEntity::ClearParent(void) +{ + tag_entity = world; + tag_index = 0; } -void NSEntity::RestoreAngles( void ) { +void +NSEntity::RestoreAngles(void) +{ angles = GetSpawnAngles(); } -void NSEntity::ClearAngles( void ) { +void +NSEntity::ClearAngles(void) +{ angles = [0, 0, 0]; } -void NSEntity::ForceNetworkUpdate( void ) { +void +NSEntity::ForceNetworkUpdate(void) +{ SendFlags = -1; } + +void +NSEntity::UseBy(entity ourActivator) +{ + if (PlayerUse) { + eActivator = (NSEntity)ourActivator; + PlayerUse(); + } +} #endif -void NSEntity::SetEffects( float newEffects ) { +void +NSEntity::SetEffects(float newEffects) +{ effects = newEffects; } -void NSEntity::SetFrame( float newFrame ) { - if ( newFrame == frame ) +void +NSEntity::SetFrame(float newFrame) +{ + if (newFrame == frame) return; frame = newFrame; @@ -361,8 +418,16 @@ void NSEntity::SetFrame( float newFrame ) { #ifdef SERVER /* check if an event callback exists */ { - int eDefEvents = tokenize(m_strModelEventCB); - string ourName = frametoname(modelindex, frame); + int eDefEvents; + string ourName; + + if (modelframecount(modelindex) > 0) { + ourName = frametoname(modelindex, frame); + } else { + return; + } + + eDefEvents = tokenize(m_strModelEventCB); for (int i = 0; i < eDefEvents; i+=3) { string testName = argv(i+0); @@ -382,52 +447,72 @@ void NSEntity::SetFrame( float newFrame ) { #endif } -void NSEntity::SetSkin( float newSkin ) { +void +NSEntity::SetSkin(float newSkin) +{ skin = newSkin; } -void NSEntity::SetOwner( entity newOwner ) { +void +NSEntity::SetOwner(entity newOwner) +{ owner = newOwner; } -void NSEntity::SetVelocity( vector vecNew ) { +void +NSEntity::SetVelocity(vector vecNew) +{ velocity = vecNew; } -void NSEntity::SetTouch( void ()newTouch ) { +void +NSEntity::SetTouch(void ()newTouch) +{ touch = newTouch; } /* we want to really use those set functions because they'll notify of any * networking related changes. otherwise we'll have to keep track of copies * that get updated every frame */ -void NSEntity::SetSendFlags( float flSendFlags ) { +void +NSEntity::SetSendFlags(float flSendFlags) +{ #ifdef SERVER SendFlags |= flSendFlags; #endif } -void NSEntity::SetMovetype( float newMovetype ) { +void +NSEntity::SetMovetype(float newMovetype) +{ movetype = newMovetype; } -void NSEntity::SetGravity( float newGrav ) { +void +NSEntity::SetGravity(float newGrav) +{ gravity = newGrav; } -void NSEntity::SetSolid( float newSolid ) { +void +NSEntity::SetSolid(float newSolid) +{ solid = newSolid; } -void NSEntity::SetScale( float newScale ) { - if ( newScale == scale ) +void +NSEntity::SetScale(float newScale) +{ + if (newScale == scale) return; scale = newScale; - setsize( this, m_vecMins * scale, m_vecMaxs * scale ); + setsize(this, m_vecMins * scale, m_vecMaxs * scale); } -void NSEntity::UpdateBounds( void ) { +void +NSEntity::UpdateBounds(void) +{ vector newMins, newMaxs; float flScale = 1.0f; @@ -435,81 +520,90 @@ void NSEntity::UpdateBounds( void ) { newMaxs = m_vecMaxs; /* avoid useless computation */ - if ( angles !=[0, 0, 0] ) { + if (angles !=[0, 0, 0]) { /* adjust bbox according to rotation */ vector vecCorner[8]; newMins = newMaxs =[0, 0, 0]; - for ( int i = 0; i < 8; i++ ) { - vecCorner[i][0] = ( i & 1 ) ? m_vecMins[0] : m_vecMaxs[0]; - vecCorner[i][1] = ( i & 2 ) ? m_vecMins[1] : m_vecMaxs[1]; - vecCorner[i][2] = ( i & 4 ) ? m_vecMins[2] : m_vecMaxs[2]; + for (int i = 0; i < 8; i++) { + vecCorner[i][0] = (i & 1) ? m_vecMins[0] : m_vecMaxs[0]; + vecCorner[i][1] = (i & 2) ? m_vecMins[1] : m_vecMaxs[1]; + vecCorner[i][2] = (i & 4) ? m_vecMins[2] : m_vecMaxs[2]; vecCorner[i] += origin; - vecCorner[i] = Math_RotateAroundPivot( vecCorner[i], origin, angles[1] ); + vecCorner[i] = rotateAroundPoint(vecCorner[i], origin, angles[1]); vecCorner[i] -= origin; - if ( !( vecCorner[i][0] <= newMaxs[0] ) ) + if (!(vecCorner[i][0] <= newMaxs[0])) newMaxs[0] = vecCorner[i][0]; - if ( !( vecCorner[i][1] <= newMaxs[1] ) ) + if (!(vecCorner[i][1] <= newMaxs[1])) newMaxs[1] = vecCorner[i][1]; - if ( !( vecCorner[i][2] <= newMaxs[2] ) ) + if (!(vecCorner[i][2] <= newMaxs[2])) newMaxs[2] = vecCorner[i][2]; - if ( !( vecCorner[i][0] >= newMins[0] ) ) + if (!(vecCorner[i][0] >= newMins[0])) newMins[0] = vecCorner[i][0]; - if ( !( vecCorner[i][1] >= newMins[1] ) ) + if (!(vecCorner[i][1] >= newMins[1])) newMins[1] = vecCorner[i][1]; - if ( !( vecCorner[i][2] >= newMins[2] ) ) + if (!(vecCorner[i][2] >= newMins[2])) newMins[2] = vecCorner[i][2]; } } /* 0.0 is never valid, if you want it to disappear do something else */ - if ( scale != 0.0 ) + if (scale != 0.0) flScale = scale; - setsize( this, newMins * flScale, newMaxs * flScale ); + setsize(this, newMins * flScale, newMaxs * flScale); } -void NSEntity::SetAngles( vector newAngles ) { +void +NSEntity::SetAngles(vector newAngles) +{ angles = newAngles; } -void NSEntity::SetAngularVelocity( vector newAvel ) { +void +NSEntity::SetAngularVelocity(vector newAvel) +{ avelocity = newAvel; } -void NSEntity::SetSize( vector newMins, vector newMaxs ) { +void +NSEntity::SetSize(vector newMins, vector newMaxs) +{ float flScale = 1.0f; m_vecMins = newMins; m_vecMaxs = newMaxs; /* 0.0 is never valid, if you want it to disappear do something else */ - if ( scale != 0.0f ) + if (scale != 0.0f) flScale = scale; - setsize( this, newMins * flScale, newMaxs * flScale ); + setsize(this, newMins * flScale, newMaxs * flScale); } -void NSEntity::SetOrigin( vector newOrigin ) { - setorigin( this, newOrigin ); +void +NSEntity::SetOrigin(vector newOrigin) { + setorigin(this, newOrigin); } -void NSEntity::SetModel( string newModel ) { +void +NSEntity::SetModel(string newModel) { m_bIsBrush = substring(newModel, 0, 1) == "*" ? true : false; model = newModel; - setmodel( this, newModel ); + setmodel(this, newModel); /* mins/maxs have been updated by setmodel */ - SetSize( mins, maxs ); + SetSize(mins, maxs); } -void NSEntity::SetModelindex( float newModelIndex ) { - if ( newModelIndex == modelindex ) +void +NSEntity::SetModelindex(float newModelIndex) { + if (newModelIndex == modelindex) return; modelindex = newModelIndex; - SetSize( mins, maxs ); + SetSize(mins, maxs); } @@ -525,281 +619,383 @@ NSEntity::AddVelocity(vector addVel) velocity += addVel; } -void NSEntity::AddEffects( float fl ) { +void +NSEntity::AddEffects(float fl) { effects |= fl; } -void NSEntity::RemoveEffects( float fl ) { +void +NSEntity::RemoveEffects(float fl) { effects &= ~fl; } -void NSEntity::AddFlags( float fl ) { +void +NSEntity::AddFlags(float fl) { flags |= fl; } -void NSEntity::RemoveFlags( float fl ) { +void +NSEntity::RemoveFlags(float fl) { flags &= ~fl; } -void NSEntity::TurnTo( float targetAngle ) { + +void +NSEntity::AddVFlags(float fl) { + vv_flags |= fl; +} + +void +NSEntity::RemoveVFlags(float fl) { + vv_flags &= ~fl; +} + +void +NSEntity::TurnTo(float targetAngle) { angles[1] = targetAngle; } -void NSEntity::TurnToPos( vector targetPos ) { - angles = vectoangles(targetPos - WorldSpaceCenter()); +void +NSEntity::TurnToPos(vector targetPos) { + angles = vectorToAngles(targetPos - WorldSpaceCenter()); } -void NSEntity::SetThink( void ( void ) func ) { +void +NSEntity::SetThink(void (void) func) { think = func; } -void NSEntity::SetNextThink( float fl ) { +void +NSEntity::SetNextThink(float fl) { float flTime = GetTime() + fl; /* HACK: to make sure things happen post-spawn */ - if ( flTime == 0.0f ) + if (flTime == 0.0f) flTime = 0.001f; - if ( flTime >= 0 ) + if (flTime >= 0) nextthink = flTime; else - EntError( "%s sets bogus nextthink value %f", classname, flTime ); + EntError("%s sets bogus nextthink value %f", classname, flTime); } -void NSEntity::ScheduleThink( void ( void ) func, float fl ) { - SetThink( func ); - SetNextThink( fl ); +void +NSEntity::ScheduleThink(void (void) func, float fl) { + SetThink(func); + SetNextThink(fl); } -vector NSEntity::GetSpawnOrigin( void ) { - return ( m_oldOrigin ); +vector +NSEntity::GetSpawnOrigin(void) { + return (m_oldOrigin); } -vector NSEntity::GetSpawnAngles( void ) { - return ( m_oldAngle ); +vector +NSEntity::GetSpawnAngles(void) { + return (m_oldAngle); } -string NSEntity::GetSpawnModel( void ) { - return ( m_oldModel ); +string +NSEntity::GetSpawnModel(void) { + return (m_oldModel); } -float NSEntity::GetEffects( void ) { - return ( effects ); +float +NSEntity::GetEffects(void) { + return (effects); } -float NSEntity::GetFrame( void ) { - return ( frame ); +float +NSEntity::GetFrame(void) { + return (frame); } -float NSEntity::GetSkin( void ) { - return ( skin ); +float +NSEntity::GetSkin(void) { + return (skin); } -float NSEntity::GetScale( void ) { - return ( scale ); +float +NSEntity::GetScale(void) { + return (scale); } -entity NSEntity::GetOwner( void ) { - return ( owner ); +entity +NSEntity::GetOwner(void) { + return (owner); } -vector NSEntity::GetVelocity( void ) { - return ( velocity ); +vector +NSEntity::GetVelocity(void) { + return (velocity); } -float NSEntity::GetSolid( void ) { - return ( solid ); +float +NSEntity::GetSolid(void) { + return (solid); } -string NSEntity::GetModel( void ) { - return ( model ); +string +NSEntity::GetModel(void) +{ + return (model); } -float NSEntity::GetModelindex( void ) { - return ( modelindex ); +float +NSEntity::GetModelindex(void) +{ + return (modelindex); } -float NSEntity::GetMovetype( void ) { - return ( movetype ); +float +NSEntity::GetMovetype(void) +{ + return (movetype); } -float NSEntity::GetGravity( void ) { - return ( gravity ); +float +NSEntity::GetGravity(void) +{ + return (gravity); } -vector NSEntity::GetAngles( void ) { - return ( angles ); +vector +NSEntity::GetAngles(void) +{ + return (angles); } -vector NSEntity::GetAngularVelocity( void ) { - return ( avelocity ); +vector +NSEntity::GetAngularVelocity(void) +{ + return (avelocity); } -vector NSEntity::GetOrigin( void ) { - return ( origin ); +vector +NSEntity::GetOrigin(void) +{ + return (origin); } -vector NSEntity::GetMins( void ) { - return ( mins ); +vector +NSEntity::GetMins(void) +{ + return (mins); } -vector NSEntity::GetMaxs( void ) { - return ( maxs ); +vector +NSEntity::GetMaxs(void) +{ + return (maxs); } -vector NSEntity::GetRealMins( void ) { - return ( m_vecMins ); +vector +NSEntity::GetRealMins(void) +{ + return (m_vecMins); } -vector NSEntity::GetRealMaxs( void ) { - return ( m_vecMaxs ); +vector +NSEntity::GetRealMaxs(void) +{ + return (m_vecMaxs); } -vector NSEntity::GetAbsoluteMins( void ) { - return ( absmin ); +vector +NSEntity::GetAbsoluteMins(void) +{ + return (absmin); } -vector NSEntity::GetAbsoluteMaxs( void ) { - return ( absmax ); +vector +NSEntity::GetAbsoluteMaxs(void) +{ + return (absmax); } -float NSEntity::GetFlags( void ) { - return ( flags ); +float +NSEntity::GetFlags(void) +{ + return (flags); } -bool NSEntity::HasFlags(float bits) { - if ( flags & bits ) - return (true); - - return (false); +float +NSEntity::GetVFlags(void) +{ + return (vv_flags); } -float NSEntity::GetNextThinkTime( void ) { - return ( nextthink ); +bool +NSEntity::HasFlags(float bits) +{ + return (flags & bits) ? (true) : (false); } -bool NSEntity::IsThinking( void ) { - return ( nextthink > GetTime() )? true : false; +bool +NSEntity::HasVFlags(float bits) +{ + return (vv_flags & bits) ? (true) : (false); } -void NSEntity::ReleaseThink( void ) { +float +NSEntity::GetNextThinkTime(void) +{ + return (nextthink); +} + +bool +NSEntity::IsThinking(void) +{ + return (nextthink > GetTime()) ? (true) : (false); +} + +void +NSEntity::ReleaseThink(void) +{ think = __NULL__; nextthink = 0.0f; } -void NSEntity::ClearVelocity( void ) { - velocity = avelocity =[0.0f, 0.0f, 0.0f]; +void +NSEntity::ThinkBusy(float busyTime) +{ + static void ThinkBusy_Done(void) { + /* Guess we're done here... */ + } + ScheduleThink(ThinkBusy_Done, busyTime); +} + +void +NSEntity::ClearVelocity(void) +{ + velocity = avelocity = [0.0f, 0.0f, 0.0f]; } #ifdef SERVER -void NSEntity::Respawn( void ) { +void +NSEntity::Respawn(void) +{ super::Respawn(); - SetSolid( m_oldSolid ); - SetAngles( GetSpawnAngles() ); - SetOrigin( GetSpawnOrigin() ); - SetModel( GetSpawnModel() ); + SetSolid(m_oldSolid); + SetAngles(GetSpawnAngles()); + SetOrigin(GetSpawnOrigin()); + SetModel(GetSpawnModel()); } -void NSEntity::Save( float handle ) { - super::Save( handle ); - SaveFloat( handle, "pvsflags", pvsflags ); - SaveFloat( handle, "_mapspawned", _mapspawned ); - SaveFloat( handle, "scale", scale ); - SaveFloat( handle, "friction", friction ); - SaveVector( handle, "m_vecMins", m_vecMins ); - SaveVector( handle, "m_vecMaxs", m_vecMaxs ); - SaveVector( handle, "m_oldOrigin", m_oldOrigin ); - SaveVector( handle, "m_oldAngle", m_oldAngle ); - SaveString( handle, "m_oldModel", m_oldModel ); - SaveFloat( handle, "m_oldSolid", m_oldSolid ); - SaveFloat( handle, "m_flTouchTime", m_flTouchTime ); - SaveBool( handle, "m_beingTouched", m_beingTouched ); - SaveEntity( handle, "m_eTouchLast", m_eTouchLast ); - SaveString( handle, "m_parent", m_parent ); - SaveString( handle, "m_parent_attachment", m_parent_attachment ); +void +NSEntity::Save(float handle) +{ + super::Save(handle); + SaveEntity(handle, "tag_entity", tag_entity); + SaveFloat(handle, "tag_index", tag_index); + SaveFloat(handle, "pvsflags", pvsflags); + SaveBool(handle, "_mapspawned", _mapspawned); + SaveFloat(handle, "scale", scale); + SaveFloat(handle, "vv_flags", vv_flags); + SaveFloat(handle, "friction", friction); + SaveVector(handle, "m_vecMins", m_vecMins); + SaveVector(handle, "m_vecMaxs", m_vecMaxs); + SaveVector(handle, "m_oldOrigin", m_oldOrigin); + SaveVector(handle, "m_oldAngle", m_oldAngle); + SaveString(handle, "m_oldModel", m_oldModel); + SaveFloat(handle, "m_oldSolid", m_oldSolid); + SaveFloat(handle, "m_flTouchTime", m_flTouchTime); + SaveBool(handle, "m_beingTouched", m_beingTouched); + SaveEntity(handle, "m_eTouchLast", m_eTouchLast); + SaveVector(handle, "m_vecEditorColor", m_vecEditorColor); } -void NSEntity::Restore( string strKey, string strValue ) { - switch ( strKey ) { +void +NSEntity::Restore(string strKey, string strValue) +{ + switch (strKey) { + case "tag_entity": + tag_entity = ReadEntity(strValue); + break; + case "tag_index": + tag_index = ReadFloat(strValue); + break; case "pvsflags": - pvsflags = stof( strValue ); + pvsflags = ReadFloat(strValue); break; case "_mapspawned": - _mapspawned = stof( strValue ); + _mapspawned = ReadBool(strValue); break; case "scale": - scale = ReadFloat( strValue ); + scale = ReadFloat(strValue); + break; + case "vv_flags": + vv_flags = ReadFloat(strValue); break; case "friction": - friction = ReadFloat( strValue ); + friction = ReadFloat(strValue); break; case "m_vecMins": - m_vecMins = ReadVector( strValue ); + m_vecMins = ReadVector(strValue); break; case "m_vecMaxs": - m_vecMaxs = ReadVector( strValue ); + m_vecMaxs = ReadVector(strValue); break; case "m_oldOrigin": - m_oldOrigin = ReadVector( strValue ); + m_oldOrigin = ReadVector(strValue); break; case "m_oldAngle": - m_oldAngle = ReadVector( strValue ); + m_oldAngle = ReadVector(strValue); break; case "m_oldModel": - m_oldModel = ReadString( strValue ); + m_oldModel = ReadString(strValue); break; case "m_oldSolid": - m_oldSolid = ReadFloat( strValue ); + m_oldSolid = ReadFloat(strValue); break; case "m_flTouchTime": - m_flTouchTime = ReadFloat( strValue ); + m_flTouchTime = ReadFloat(strValue); break; case "m_beingTouched": - m_beingTouched = ReadBool( strValue ); + m_beingTouched = ReadBool(strValue); break; case "m_eTouchLast": - m_eTouchLast = ReadEntity( strValue ); + m_eTouchLast = ReadEntity(strValue); break; - case "m_parent": - m_parent = ReadString( strValue ); - break; - case "m_parent_attachment": - m_parent_attachment = ReadString( strValue ); + case "m_vecEditorColor": + m_vecEditorColor = ReadVector(strValue); break; default: - super::Restore( strKey, strValue ); + super::Restore(strKey, strValue); break; } } -void NSEntity::Input( entity eAct, string strInput, string strData ) { - switch ( strInput ) { +void +NSEntity::Input(entity eAct, string strInput, string strData) +{ + switch (strInput) { case "Kill": Destroy(); break; case "KillHierarchy": /* this works because ents are basically just entnums */ - for ( entity e = world; ( e = findfloat( e, ::owner, this ) ); ) { - NSEntity ent = ( NSEntity ) e; + for (entity e = world; (e = findfloat(e, ::owner, this));) { + NSEntity ent = (NSEntity) e; ent.Destroy(); } Destroy(); break; case "SetParent": - SetParent( strData ); + SetParent(strData); break; case "SetParentAttachment": - SetParentAttachment( strData ); + SetParentAttachment(strData); break; case "ClearParent": ClearParent(); break; case "Use": - eActivator = eAct; + eActivator = (NSEntity)eAct; - if ( PlayerUse ) + if (PlayerUse) PlayerUse(); break; case "SpawnDef": @@ -817,10 +1013,9 @@ void NSEntity::Input( entity eAct, string strInput, string strData ) { break; case "AddVelocity": vector velAdd = stov(strData); - makevectors(angles); - velocity += v_forward * velAdd[0]; - velocity += v_right * velAdd[1]; - velocity += v_up * velAdd[2]; + velocity += GetForward() * velAdd[0]; + velocity += GetRight() * velAdd[1]; + velocity += GetUp() * velAdd[2]; break; case "Shockwave": int c = tokenize(strData); @@ -848,45 +1043,62 @@ void NSEntity::Input( entity eAct, string strInput, string strData ) { msg_entity = this; multicast(origin, MULTICAST_PVS); break; + case "SetOrigin": + SetOrigin(stov(strData)); + break; + case "SetSpawnOrigin": + m_oldOrigin = stov(strData); + break; + case "SetEditorColor": + m_vecEditorColor = ReadVector(strData); + break; + case "Respawn": + Respawn(); + break; default: - NSTrigger::Input( eAct, strInput, strData ); + NSTrigger::Input(eAct, strInput, strData); } } #endif -void NSEntity::SpawnKey( string strKey, string strValue ) { +void +NSEntity::SpawnKey(string strKey, string strValue) +{ bool tempCheck = false; /* we do re-read a lot of the builtin fields in case we want to set defaults. just in case anybody is wondering. */ - switch ( strKey ) { + switch (strKey) { case "spawnflags": - spawnflags = ReadFloat( strValue ); + spawnflags = ReadFloat(strValue); break; case "origin": - origin = ReadVector( strValue ); + origin = ReadVector(strValue); break; case "model": model = ReadString(strValue); break; case "angles": - angles = ReadVector( strValue ); + angles = ReadVector(strValue); break; case "angle": - angles[1] = ReadFloat( strValue ); + angles[1] = ReadFloat(strValue); break; case "solid": - solid = ReadFloat( strValue ); + solid = ReadFloat(strValue); break; case "friction": - friction = ReadFloat( strValue ); + friction = ReadFloat(strValue); + break; + case "editor_color": + m_vecEditorColor = ReadVector(strValue); break; #ifdef SERVER case "health": - health = ReadFloat( strValue ); + health = ReadFloat(strValue); break; case "movewith": case "parentname": - SetParent( ReadString(strValue) ); + SetParent(ReadString(strValue)); break; case "ignorepvs": tempCheck = ReadBool(strValue); @@ -898,18 +1110,26 @@ void NSEntity::SpawnKey( string strKey, string strValue ) { break; #endif + case "editor_mins": + case "editor_maxs": + case "editor_usage": + case "editor_model": case "_minlight": break; default: - super::SpawnKey( strKey, strValue ); + super::SpawnKey(strKey, strValue); break; } } -void NSEntity::OnRemoveEntity( void ) { +void +NSEntity::OnRemoveEntity(void) +{ } -void NSEntity::Destroy( void ) { +void +NSEntity::Destroy(void) +{ removed = 1; /* mark this as cleanly removed */ OnRemoveEntity(); customphysics = __NULL__; @@ -917,147 +1137,170 @@ void NSEntity::Destroy( void ) { solid = 0; movetype = 0; classname = 0; - ScheduleThink(Util_Destroy, 0.0f ); + ScheduleThink(Util_Destroy, 0.0f); } -void NSEntity::Show( void ) { +void +NSEntity::Show(void) +{ effects &= ~EF_NODRAW; } -void NSEntity::Hide( void ) { +void +NSEntity::Hide(void) +{ effects |= EF_NODRAW; } -bool NSEntity::IsHidden( void ) { - return ( effects & EF_NODRAW ) ? true : false; +bool +NSEntity::IsHidden(void) +{ + return (effects & EF_NODRAW) ? true : false; } -void NSEntity::Disappear( void ) { - modelindex = 0; - solid = SOLID_NOT; +void +NSEntity::Disappear(void) +{ + modelindex = (0); + SetSolid(SOLID_NOT); } -void NSEntity::MakeStatic( void ) { - makestatic( this ); +void +NSEntity::MakeStatic(void) +{ + makestatic(this); } bool NSEntity::CanSpawn(bool clientSide) { - /* in most cases, we don't need these to spawn on the client-side */ - if (clientSide) - return false; - else - return true; + return !(clientSide); } -bool NSEntity::WithinBounds( entity check ) { - if not ( check.absmin[0] >= absmin[0] && check.absmax[0] <= absmax[0] ) - return ( false ); - if not ( check.absmin[1] >= absmin[1] && check.absmax[1] <= absmax[1] ) - return ( false ); - if not ( check.absmin[2] >= absmin[2] && check.absmax[2] <= absmax[2] ) - return ( false ); +bool +NSEntity::WithinBounds(entity check) +{ + if not (check.absmin[0] >= absmin[0] && check.absmax[0] <= absmax[0]) + return (false); + if not (check.absmin[1] >= absmin[1] && check.absmax[1] <= absmax[1]) + return (false); + if not (check.absmin[2] >= absmin[2] && check.absmax[2] <= absmax[2]) + return (false); - return ( true ); + return (true); } -bool NSEntity::IntersectsWith( entity check ) { - if not ( check.origin[0] >= absmin[0] && check.origin[0] <= absmax[0] ) - return ( false ); - if not ( check.origin[1] >= absmin[1] && check.origin[1] <= absmax[1] ) - return ( false ); - if not ( check.origin[2] >= absmin[2] && check.origin[2] <= absmax[2] ) - return ( false ); +bool +NSEntity::IntersectsWith(entity check) +{ + if not (check.origin[0] >= absmin[0] && check.origin[0] <= absmax[0]) + return (false); + if not (check.origin[1] >= absmin[1] && check.origin[1] <= absmax[1]) + return (false); + if not (check.origin[2] >= absmin[2] && check.origin[2] <= absmax[2]) + return (false); - return ( true ); + return (true); } -bool NSEntity::StartSound( string strSample, float channel, float flags, bool broadcast ) { - if not ( whichpack( strcat( "sound/", strSample ) ) ) - return ( false ); +bool +NSEntity::StartSound(string strSample, float channel, float flags, bool broadcast) +{ + if not (whichpack(strcat("sound/", strSample))) + return (false); - if ( broadcast ) { - sound( this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_FOLLOW ); + if (broadcast) { + sound(this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_FOLLOW); } else { #ifdef SERVER msg_entity = this; - sound( this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_UNICAST | SOUNDFLAG_FOLLOW); + sound(this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_UNICAST | SOUNDFLAG_FOLLOW); msg_entity = __NULL__; #else - sound( this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_FOLLOW ); + sound(this, channel, strSample, 1.0f, ATTN_NORM, 0, SOUNDFLAG_FOLLOW); #endif } - SndEntLog( "%s (chan: %d bcast: %d) (%v)", strSample, channel, broadcast, origin ); + SndEntLog("%s (chan: %d bcast: %d) (%v)", strSample, channel, broadcast, origin); - return ( true ); + return (true); } -bool NSEntity::StartSoundDef( string strSample, float channel, bool broadcast ) { - SndEntLog( "%s (chan: %d bcast: %d)", strSample, channel, broadcast ); - Sound_Play( this, channel, strSample ); - return ( true ); -} - -void NSEntity::StopSound( float channel, bool broadcast ) { - sound( this, channel, "common/null.wav", 0.1f, ATTN_NORM ); -} - -vector NSEntity::NearestWallPointForRadius(float radius) +bool +NSEntity::StartSoundDef(string strSample, float channel, bool broadcast) { - vector vecRadius = [radius, radius, radius]; - tracebox(origin, -vecRadius, vecRadius, origin, MOVE_EVERYTHING, this); + SndEntLog("%s (chan: %d bcast: %d)", strSample, channel, broadcast); + Sound_Play(this, channel, strSample); + return (true); +} - if (trace_fraction <= 1.0) { - return trace_endpos; +void +NSEntity::StopSound(float channel, bool broadcast) +{ + if (broadcast) { + Sound_Stop(this, channel); } else { - return origin; +#ifdef SERVER + msg_entity = this; + sound(this, channel, "common/null.wav", 1.0f, ATTN_NORM, 100, SOUNDFLAG_UNICAST | SOUNDFLAG_FOLLOW, 0 ); + msg_entity = __NULL__; +#else + Sound_Stop(this, channel); +#endif } } -void NSEntity::HandleThink( void ) { +vector +NSEntity::NearestWallPointForRadius(float radius) +{ + vector vecRadius = [radius, radius, radius]; + tracebox(origin, -vecRadius, vecRadius, origin, MOVE_EVERYTHING, this); + return (trace_fraction <= 1.0) ? trace_endpos : origin; +} + +void +NSEntity::HandleThink(void) +{ /* support for think/nextthink */ - if ( think && nextthink > 0.0f ) { - if ( nextthink < time ) { + if (think && nextthink > 0.0f) { + if (nextthink < time) { nextthink = 0.0f; think(); } } } -bool NSEntity::IsFacing(entity target) +bool +NSEntity::IsFacing(entity target) { - vector vecDiff = normalize(target.origin - origin); - makevectors(angles); - return ((vecDiff * v_forward) > 0 ) ? true : false; + vector vecDiff = vectorNormalize(target.origin - origin); + return ((vecDiff * GetForward()) > 0) ? true : false; } -bool NSEntity::IsFacingPosition(vector targetPos) +bool +NSEntity::IsFacingPosition(vector targetPos) { - vector vecDiff = normalize(targetPos - origin); - makevectors(angles); - return ((vecDiff * v_forward) > 0 ) ? true : false; + vector vecDiff = vectorNormalize(targetPos - origin); + return ((vecDiff * GetForward()) > 0) ? true : false; } float NSEntity::GetSpawnAge(void) { - return time - m_flSpawnTime; + return (time - m_flSpawnTime); } float NSEntity::GetSpawnTime(void) { - return m_flSpawnTime; + return (m_flSpawnTime); } void NSEntity::Transport(vector new_pos, vector new_ang) { - float flSpeed = vlen(this.GetVelocity()); - makevectors(new_ang); - SetVelocity(v_forward * flSpeed); + float flSpeed = length(this.GetVelocity()); + SetVelocity(anglesToForward(new_ang) * flSpeed); SetOrigin(new_pos); SetAngles(new_ang); @@ -1079,58 +1322,63 @@ NSEntity::GetNearbySpot(void) { vector testPos; float minDist = maxs[0]; - makevectors([0,0,0]); + vector fwdDir, rightDir, upDir; + + fwdDir = anglesToForward([0,0,0]); + rightDir = anglesToRight([0,0,0]); + upDir = anglesToUp([0,0,0]); /* space in front? */ - testPos = GetOrigin() + v_forward * minDist; + testPos = GetOrigin() + fwdDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* behind? */ - testPos = GetOrigin() - v_forward * minDist; + testPos = GetOrigin() - fwdDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; + /* left? */ - testPos = GetOrigin() - v_right * minDist; + testPos = GetOrigin() - rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* right? */ - testPos = GetOrigin() + v_right * minDist; + testPos = GetOrigin() + rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* front left? */ - testPos = GetOrigin() + v_forward * minDist - v_right * minDist; + testPos = GetOrigin() + fwdDir * minDist - rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* front right? */ - testPos = GetOrigin() + v_forward * minDist + v_right * minDist; + testPos = GetOrigin() + fwdDir * minDist + rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* back left? */ - testPos = GetOrigin() - v_forward * minDist - v_right * minDist; + testPos = GetOrigin() - fwdDir * minDist - rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) return testPos; /* back right? */ - testPos = GetOrigin() - v_forward * minDist + v_right * minDist; + testPos = GetOrigin() - fwdDir * minDist + rightDir * minDist; tracebox(testPos, mins, maxs, testPos, MOVE_NORMAL, this); if (trace_fraction == 1.0f) diff --git a/src/shared/NSItem.h b/src/shared/NSItem.h index 51aad26c..a789e510 100644 --- a/src/shared/NSItem.h +++ b/src/shared/NSItem.h @@ -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 \ No newline at end of file + string m_strInvWeapon; +}; \ No newline at end of file diff --git a/src/shared/NSItem.qc b/src/shared/NSItem.qc index 11f065d7..f8cf5af1 100644 --- a/src/shared/NSItem.qc +++ b/src/shared/NSItem.qc @@ -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 + diff --git a/src/shared/NSMonster.h b/src/shared/NSMonster.h index acdc0b63..3e8a5f23 100644 --- a/src/shared/NSMonster.h +++ b/src/shared/NSMonster.h @@ -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); diff --git a/src/shared/NSMonster.qc b/src/shared/NSMonster.qc index 1ea134e8..dd795579 100644 --- a/src/shared/NSMonster.qc +++ b/src/shared/NSMonster.qc @@ -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) { diff --git a/src/shared/NSNavAI.h b/src/shared/NSNavAI.h index a9db8e30..dbebd1ba 100644 --- a/src/shared/NSNavAI.h +++ b/src/shared/NSNavAI.h @@ -16,12 +16,14 @@ var bool autocvar_ai_debugNav = false; void -_NSNavAI_Log(string msg) +_NSNavAI_Log(string className, string functionName, float edictNum, string warnMessage) { - if (autocvar_ai_debugNav == true) - print(sprintf("%f %s\n", time, msg)); + if (autocvar_g_developerTimestamps) + printf("^9%f ^5%s (%d) ^7: %s\n", time, functionName, edictNum, warnMessage); + else + printf("^5%s (%d) ^7: %s\n", functionName, edictNum, warnMessage); } -#define NSNavAI_Log(...) _NSNavAI_Log(sprintf(__VA_ARGS__)) +#define NSNavAI_Log(...) _NSNavAI_Log(classname, __FUNC__, num_for_edict(this), sprintf(__VA_ARGS__)) #ifndef MAX_AMMO_TYPES #define MAX_AMMO_TYPES 16 @@ -34,33 +36,55 @@ types of pathfinding in the future. class NSNavAI:NSSurfacePropEntity { -private: -#ifdef SERVER - /* pathfinding */ - int m_iNodes; - int m_iCurNode; - nodeslist_t *m_pRoute; - vector m_vecLastNode; - vector m_vecTurnAngle; - string m_pathTarget; - NSEntity m_pathEntity; - float _m_flRouteGiveUp; - vector _m_vecRoutePrev; - vector m_vecRouteEntity; - entity m_eFollowing; - - /* These are defined in side defs\*.def, ammo_types and ammo_names */ - int m_iAmmoTypes[MAX_AMMO_TYPES]; -#endif public: void NSNavAI(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); + + /** Overridable: Returns the desired maximum forward movement speed. */ + virtual float GetForwardSpeed(void); + /** Overridable: Returns the desired maximum side movement speed. */ + virtual float GetSideSpeed(void); + /** Overridable: Returns the desired maximum backwardss movement speed. */ + virtual float GetBackSpeed(void); + + /** Returns `true` when the entity is ducked/crouching */ + nonvirtual bool IsCrouching(void); + /** Returns `true` when the entity is ducked/crouching */ + nonvirtual bool IsProne(void); + /** Returns `true` when the entity is standing, walking. */ + nonvirtual bool IsStanding(void); + /** Returns `true` when the entity is running. */ + nonvirtual bool IsSprinting(void); + /** Returns `true` when the entity is leaning */ + nonvirtual bool IsLeaning(void); + + /* ammo handling */ + /** Gives ammo up of a specified type. Returns `false` when impossible. */ + nonvirtual bool GiveAmmo(int, int); + /** Uses ammo up of a specified type. Returns `false` when impossible. */ + nonvirtual bool UseAmmo(int, int); + + /* inventory handling */ + /** Adds a named NSItem to the inventory. Returns `false` when impossible. */ + nonvirtual bool GiveItem(string); + /** Removes a named NSItem from the inventory Returns `false` when impossible. */ + nonvirtual bool RemoveItem(string); + #ifdef SERVER /* overrides */ virtual void Save(float); virtual void Restore(string,string); virtual void RestoreComplete(void); + virtual void DebugDraw(void); /* methods we'd like others to override */ /** Returns if this class is capable of crouching. */ @@ -69,6 +93,11 @@ public: nonvirtual vector GetRouteMovevalues(void); /** Returns the current movement direction. */ nonvirtual vector GetRouteDirection(void); + /** Sets the scale on the movement before physics are run. This is used to simulate walking. 0 is treated as 1 (no change).*/ + nonvirtual void SetMoveSpeedScale(float); + /** Returns the movement speed scale. */ + nonvirtual float GetMoveSpeedScale(void); + /** Called when the object is done moving to its destination. */ virtual void RouteEnded(void); /** When called, will wipe any memory of an ongoing route. */ @@ -83,5 +112,27 @@ public: virtual void ChasePath(string startPath); /** Internal use only. Called every frame to see our route progression. */ virtual void CheckRoute_Path(void); + /** Overridable: Called when the entity is ready to move. When overridden, will no longer move until super function is called, or physics is handled within. */ + virtual void Physics_Run(void); #endif + +private: +#ifdef SERVER + /* pathfinding */ + int m_iNodes; + int m_iCurNode; + nodeslist_t *m_pRoute; + vector m_vecLastNode; + vector m_vecTurnAngle; + string m_pathTarget; + NSEntity m_pathEntity; + float _m_flRouteGiveUp; + vector _m_vecRoutePrev; + vector m_vecRouteEntity; + entity m_eFollowing; + float m_flMoveSpeedKey; +#endif + + /* These are defined in side defs\*.def, ammo_types and ammo_names */ + int m_iAmmoTypes[MAX_AMMO_TYPES]; }; diff --git a/src/shared/NSNavAI.qc b/src/shared/NSNavAI.qc index 2c9e927b..fa607b69 100644 --- a/src/shared/NSNavAI.qc +++ b/src/shared/NSNavAI.qc @@ -23,12 +23,86 @@ NSNavAI::NSNavAI(void) m_pRoute = __NULL__; m_vecLastNode = [0,0,0]; m_vecTurnAngle = [0,0,0]; + m_flMoveSpeedKey = 0.0f; _m_flRouteGiveUp = 0.0f; +#endif for (int i = 0; i < MAX_AMMO_TYPES; i++) m_iAmmoTypes[i] = 0; -#endif +} + +bool +NSNavAI::IsCrouching(void) +{ + return HasVFlags(VFL_CROUCHING); +} + +bool +NSNavAI::IsProne(void) +{ + return HasVFlags(VFL_PRONE); +} + +bool +NSNavAI::IsStanding(void) +{ + return !HasVFlags(VFL_PRONE | VFL_CROUCHING | VFL_SPRINTING); +} + +bool +NSNavAI::IsSprinting(void) +{ + return HasVFlags(VFL_SPRINTING); +} + +bool +NSNavAI::IsLeaning(void) +{ + return (false); +} + +bool +NSNavAI::CanSprint(void) +{ + return (false); +} + +bool +NSNavAI::CanProne(void) +{ + return (false); +} + +bool +NSNavAI::CanLean(void) +{ + return (false); +} + +bool +NSNavAI::CanCrouch(void) +{ + return (false); +} + +/* filled these in with the (default) client side player movement values */ +float +NSNavAI::GetForwardSpeed(void) +{ + return (PMOVE_FORWARD_SPEED); +} + +float +NSNavAI::GetSideSpeed(void) +{ + return (PMOVE_SIDE_SPEED); +} + +float +NSNavAI::GetBackSpeed(void) +{ + return (PMOVE_BACK_SPEED); } #ifdef SERVER @@ -40,6 +114,7 @@ NSNavAI::Save(float handle) SaveInt(handle, "m_iCurNode", m_iCurNode); SaveVector(handle, "m_vecLastNode", m_vecLastNode); SaveVector(handle, "m_vecTurnAngle", m_vecTurnAngle); + SaveFloat(handle, "m_flMoveSpeedKey", m_flMoveSpeedKey); } void @@ -58,6 +133,9 @@ NSNavAI::Restore(string strKey, string strValue) case "m_vecTurnAngle": m_vecTurnAngle = ReadVector(strValue); break; + case "m_flMoveSpeedKey": + m_flMoveSpeedKey = ReadFloat(strValue); + break; default: super::Restore(strKey, strValue); } @@ -76,12 +154,6 @@ NSNavAI::RestoreComplete(void) #ifdef SERVER -bool -NSNavAI::CanCrouch(void) -{ - return false; -} - void NSNavAI::RouteEnded(void) { @@ -121,8 +193,11 @@ NSNavAI::CheckRoute(void) return; if (_m_flRouteGiveUp < time) { + float distanceToLastFrame = distanceSquared(_m_vecRoutePrev, origin); + printf("distanceToLastFrame: %f\n", distanceToLastFrame); + /* 50 units in 2 seconds is not good. */ - if (vlen(_m_vecRoutePrev - origin) < 50.0f) { + if (distanceToLastFrame < 50.0f) { /* HACK: for followers */ if (m_eFollowing) { RouteToPosition(m_eFollowing.origin); @@ -204,12 +279,12 @@ NSNavAI::CheckRoute(void) /* test up */ src = origin + [0,0,24]; makevectors(angles); - traceline(src, src + v_forward * 128, MOVE_NORMAL, this); + traceline(src, src + anglesToForward(angles) * 128, MOVE_NORMAL, this); /* we hit something */ if (trace_fraction < 1.0) { src = origin + [0,0, -8]; - traceline(src, src + v_forward * 128, MOVE_NORMAL, this); + traceline(src, src + anglesToForward(angles) * 128, MOVE_NORMAL, this); /* we can crouch here, so let's do it */ if (trace_fraction >= 1.0) @@ -218,7 +293,7 @@ NSNavAI::CheckRoute(void) /* entire way-link needs to be crouched. that's the law of the land */ if (shouldcrouch || Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_CROUCH) - input_buttons |= INPUT_BUTTON8; + input_buttons |= INPUT_CROUCH; } /*if (flDist == m_flLastDist) { @@ -240,28 +315,32 @@ vector NSNavAI::GetRouteMovevalues(void) { vector vecDirection; + vector fwdDir, rightDir, upDir; + + fwdDir = anglesToForward(input_angles); + rightDir = anglesToRight(input_angles); + upDir = anglesToUp(input_angles); if (m_pathTarget) { - vecDirection = normalize(m_pathEntity.GetOrigin() - GetOrigin()); + vecDirection = vectorNormalize(m_pathEntity.GetOrigin() - GetOrigin()); } else { if (!m_iNodes) - return [0,0,0]; + return m_vecLastNode; if (m_iCurNode < 0) - vecDirection = normalize(m_vecLastNode - GetOrigin()); + vecDirection = vectorNormalize(m_vecLastNode - GetOrigin()); else - vecDirection = normalize(m_pRoute[m_iCurNode].dest - GetOrigin()); + vecDirection = vectorNormalize(m_pRoute[m_iCurNode].dest - GetOrigin()); } - makevectors(input_angles); - return [v_forward * vecDirection, v_right * vecDirection, v_up * vecDirection]; + return [fwdDir * vecDirection, rightDir * vecDirection, upDir * vecDirection]; } vector NSNavAI::GetRouteDirection(void) { if (m_pathTarget) { - return vectoangles(m_pathEntity.GetOrigin() - GetOrigin()); + return vectorToAngles(m_pathEntity.GetOrigin() - GetOrigin()); } else { if (!m_iNodes) { @@ -269,9 +348,9 @@ NSNavAI::GetRouteDirection(void) } if (m_iCurNode < 0) { - return vectoangles(m_vecLastNode - origin); + return vectorToAngles(m_vecLastNode - origin); } else { - return vectoangles(m_pRoute[m_iCurNode].dest - origin); + return vectorToAngles(m_pRoute[m_iCurNode].dest - origin); } } } @@ -282,6 +361,30 @@ NSNavAI::RouteToPosition(vector destination) RouteToPositionDenyFlags(destination, 0i); } +void +NSNavAI::DebugDraw(void) +{ + vector vecStart = GetOrigin(); + vector vecEnd; + vector beamColor = [1,1,1]; + float frac = 1.0 / m_iNodes; + + for (int i = m_iCurNode; i < m_iNodes; i++) { + if (m_iCurNode < 0) + continue; + + vecEnd = m_pRoute[i].dest; + R_BeginPolygon("", 0, 0); + R_PolygonVertex(vecStart, [1,1], beamColor, 1); + R_PolygonVertex(vecEnd, [0,1], beamColor, 1); + R_EndPolygon(); + vecStart = vecEnd; + beamColor[0] -= frac; + beamColor[1] -= frac; + beamColor[2] -= frac; + } +} + void NSNavAI::RouteToPositionDenyFlags(vector destination, int denylinkflags) { @@ -362,4 +465,75 @@ NSNavAI::RouteClear(void) memfree(m_pRoute); NSNavAI_Log("Actor %S (%s) cleared their route.", netname, classname); } + +void +NSNavAI::SetMoveSpeedScale(float newValue) +{ + m_flMoveSpeedKey = newValue; +} + +float +NSNavAI::GetMoveSpeedScale(void) +{ + return (m_flMoveSpeedKey == 0.0) ? 1.0f : m_flMoveSpeedKey; +} + +void +NSNavAI::Physics_Run(void) +{ + input_movevalues *= GetMoveSpeedScale(); + + if (CanCrouch()) + PMoveCustom_RunCrouchPhysics(this); + else + PMoveCustom_RunPlayerPhysics(this); + + SetOrigin(origin); +} #endif + +bool +NSNavAI::GiveAmmo(int ammoType, int ammoAmount) +{ + /* bounds check */ + if (ammoType < 0i || ammoType >= MAX_AMMO_TYPES) + return (false); + + /* already at max-ammo? */ + if (m_iAmmoTypes[ammoType] >= 255i) + return (false); + + m_iAmmoTypes[ammoType] += ammoAmount; + + if (m_iAmmoTypes[ammoType] >= 255i) + m_iAmmoTypes[ammoType] = 255i; + + return (true); +} + +bool +NSNavAI::UseAmmo(int ammoType, int ammoAmount) +{ + /* bounds check */ + if (ammoType < 0i || ammoType >= MAX_AMMO_TYPES) + return (false); + + /* will underflow when used. */ + if ((m_iAmmoTypes[ammoType] - ammoAmount) < 0i) + return (false); + + m_iAmmoTypes[ammoType] -= ammoAmount; + return (true); +} + +bool +NSNavAI::GiveItem(string itemName) +{ + return (false); +} + +bool +NSNavAI::RemoveItem(string itemName) +{ + return (false); +} diff --git a/src/shared/NSPhysicsEntity.qc b/src/shared/NSPhysicsEntity.qc index ed5d5aab..dcec6eb4 100644 --- a/src/shared/NSPhysicsEntity.qc +++ b/src/shared/NSPhysicsEntity.qc @@ -445,9 +445,9 @@ NSPhysicsEntity::_TouchThink(void) if (trace_startsolid) { if (trace_ent.flags & FL_CLIENT) { if (trace_ent.absmin[2] < absmax[2]) { + vector dirVec = trace_endpos - trace_ent.origin; Wake(); - makevectors(vectoangles(trace_endpos - trace_ent.origin)); - ApplyTorqueCenter(v_forward * 240); + ApplyTorqueCenter(anglesToForward(vectorToAngles(dirVec)) * 240); } else { Sleep(); velocity = [0,0,0]; @@ -485,14 +485,8 @@ NSPhysicsEntity::_TouchThink(void) wantangle[0] = (int)((angles[0] + 45) / 90) * 90; wantangle[1] = angles[1]; wantangle[2] = (int)((angles[2] + 45) / 90) * 90; - - makevectors(angles); - angles = v_forward; - makevectors(wantangle); - newangle[0] = Math_Lerp(angles[0], v_forward[0], frametime * 5.0f); - newangle[1] = Math_Lerp(angles[1], v_forward[1], frametime * 5.0f); - newangle[2] = Math_Lerp(angles[2], v_forward[2], frametime * 5.0f); - angles = vectoangles(newangle); + newangle = vectorLerp(anglesToForward(angles), anglesToForward(wantangle), frametime * 5.0f); + angles = vectorToAngles(newangle); } } #endif diff --git a/src/shared/NSPointTrigger.h b/src/shared/NSPointTrigger.h index 45527569..60a54dbf 100644 --- a/src/shared/NSPointTrigger.h +++ b/src/shared/NSPointTrigger.h @@ -33,6 +33,7 @@ public: nonvirtual void InitPointTrigger(void); #ifdef SERVER + virtual void SpawnKey(string, string); virtual void Save(float); virtual void Restore(string, string); diff --git a/src/shared/NSPointTrigger.qc b/src/shared/NSPointTrigger.qc index 6d2725c7..6b48776f 100644 --- a/src/shared/NSPointTrigger.qc +++ b/src/shared/NSPointTrigger.qc @@ -36,7 +36,10 @@ NSPointTrigger::InitPointTrigger(void) #ifdef SERVER m_bEnabled = (m_bStartDisabled) ? false : true; - m_strDebugTexture = strcat("textures/editor/", classname); + + if (m_strDebugTexture == __NULL__) { + m_strDebugTexture = strcat("textures/editor/", classname); + } #endif } @@ -44,16 +47,32 @@ void NSPointTrigger::DebugDraw(void) { #ifdef SERVER + vector centerPos = WorldSpaceCenter(); + super::DebugDraw(); R_BeginPolygon(m_strDebugTexture, 0, 0); - R_PolygonVertex(GetOrigin() + v_right * 16 - v_up * 16, [1,1], [1,1,1], 1.0f); - R_PolygonVertex(GetOrigin() - v_right * 16 - v_up * 16, [0,1], [1,1,1], 1.0f); - R_PolygonVertex(GetOrigin() - v_right * 16 + v_up * 16, [0,0], [1,1,1], 1.0f); - R_PolygonVertex(GetOrigin() + v_right * 16 + v_up * 16, [1,0], [1,1,1], 1.0f); + R_PolygonVertex(centerPos + v_right * 16 - v_up * 16, [1,1], [1,1,1], 1.0f); + R_PolygonVertex(centerPos - v_right * 16 - v_up * 16, [0,1], [1,1,1], 1.0f); + R_PolygonVertex(centerPos - v_right * 16 + v_up * 16, [0,0], [1,1,1], 1.0f); + R_PolygonVertex(centerPos + v_right * 16 + v_up * 16, [1,0], [1,1,1], 1.0f); R_EndPolygon(); #endif } #ifdef SERVER + +void +NSPointTrigger::SpawnKey(string strKey, string strValue) +{ + switch (strKey) { + case "editor_sprite": + m_strDebugTexture = ReadString(strValue); + break; + default: + super::SpawnKey(strKey, strValue); + break; + } +} + void NSPointTrigger::Save(float handle) { diff --git a/src/shared/NSRenderableEntity.qc b/src/shared/NSRenderableEntity.qc index 6edee1db..8b096b3b 100644 --- a/src/shared/NSRenderableEntity.qc +++ b/src/shared/NSRenderableEntity.qc @@ -1162,10 +1162,20 @@ NSRenderableEntity::SpawnKey(string strKey, string strValue) case "scale": scale = ReadFloat(strValue); break; + case "modelscale_vec": case "modelstretch": case "axialscale": m_vecAxialScale = ReadVector(strValue); break; + case "lightingPrecalc": + m_vecRenderColor = ReadVector(strValue); + m_flRenderAmt = 1.0f; +#ifdef SERVER + m_oldiRenderMode = m_iRenderMode; + m_oldflRenderAmt = m_flRenderAmt; + m_oldvecRenderColor = m_vecRenderColor; +#endif + break; case "skin": skin = ReadFloat(strValue); break; diff --git a/src/shared/NSSpawnPoint.h b/src/shared/NSSpawnPoint.h index f3d74259..f8d085b2 100644 --- a/src/shared/NSSpawnPoint.h +++ b/src/shared/NSSpawnPoint.h @@ -23,4 +23,9 @@ public: /* overrides */ virtual void Respawn(void); + virtual void SpawnKey(string, string); + +private: + vector m_vecMins; + vector m_vecMaxs; }; diff --git a/src/shared/NSSpawnPoint.qc b/src/shared/NSSpawnPoint.qc index e44e9138..c1475230 100644 --- a/src/shared/NSSpawnPoint.qc +++ b/src/shared/NSSpawnPoint.qc @@ -22,10 +22,36 @@ NSSpawnPoint::NSSpawnPoint(void) void NSSpawnPoint::Respawn(void) { + vector newMins, newMaxs; + + if (m_vecMins == g_vec_null) { + newMins = VEC_HULL_MIN; + newMaxs = VEC_HULL_MAX; + } else { + newMins = m_vecMins; + newMaxs = m_vecMaxs; + } + InitPointTrigger(); setorigin_safe(this, GetSpawnOrigin()); - SetSize(VEC_HULL_MIN, VEC_HULL_MAX); + SetSize(newMins, newMaxs); SetSolid(SOLID_NOT); SetMovetype(MOVETYPE_NONE); botinfo = BOTINFO_SPAWNPOINT; } + +void +NSSpawnPoint::SpawnKey(string keyName, string setValue) +{ + switch (keyName) { + case "mins": + m_vecMins = ReadVector(setValue); + break; + case "maxs": + m_vecMaxs = ReadVector(setValue); + break; + default: + super::SpawnKey(keyName, setValue); + } +} + diff --git a/src/shared/NSSurfacePropEntity.h b/src/shared/NSSurfacePropEntity.h index 0f858d21..26297e51 100644 --- a/src/shared/NSSurfacePropEntity.h +++ b/src/shared/NSSurfacePropEntity.h @@ -70,14 +70,15 @@ public: virtual void ReceiveEntity(float,float); #endif + /** Returns whether or not this entity is on fire. */ + nonvirtual bool IsOnFire(void); + /* new */ #ifdef SERVER /** Sets the entity on fire. */ nonvirtual void Ignite(entity, float, int); /** If the entity is on fire, it'll have it extinguished */ nonvirtual void Extinguish(void); - /** Returns whether or not this entity is on fire. */ - nonvirtual bool IsOnFire(void); /** Called whenever the entity receives damage. */ virtual void Pain(void); /** Called when the health is equal or below 0 */ @@ -85,13 +86,25 @@ public: /** Returns whether or not the entity is alive. */ virtual bool IsAlive(void); - /** Sets whether the entity can bleed. */ - nonvirtual void SetCanBleed(bool); /** Returns whether the entity can bleed. */ nonvirtual bool CanBleed(void); + /** Returns whether the entity can be damaged. */ + nonvirtual bool IsVulnerable(void); /* Generic Damage */ - /** Sets whether the entity can take damage */ + /** Makes the entity vulnerable if it wasn't already. */ + nonvirtual void EnableBleeding(void); + /** Makes the entity invulnerable if it wasn't already. */ + nonvirtual void DisableBleeding(void); + /** Makes the entity vulnerable if it wasn't already. */ + nonvirtual void EnableAimAssist(void); + /** Makes the entity invulnerable if it wasn't already. */ + nonvirtual void DisableAimAssist(void); + /** Makes the entity vulnerable if it wasn't already. */ + nonvirtual void MakeVulnerable(void); + /** Makes the entity invulnerable if it wasn't already. */ + nonvirtual void MakeInvulnerable(void); + /** Deprecated: Sets whether the entity can take damage */ nonvirtual void SetTakedamage(float); /** Sets the current health of the entity. */ nonvirtual void SetHealth(float); @@ -180,9 +193,12 @@ private: string m_strPropData; float m_flDeathTime; + bool m_bAutoAim; + bool m_bTakesDamage; nonvirtual void _SurfaceDataFinish(void); nonvirtual void _PropDataFinish(void); + nonvirtual void _UpdateTakedamage(void); #endif }; diff --git a/src/shared/NSSurfacePropEntity.qc b/src/shared/NSSurfacePropEntity.qc index 0b7954a0..8e55dad0 100644 --- a/src/shared/NSSurfacePropEntity.qc +++ b/src/shared/NSSurfacePropEntity.qc @@ -37,7 +37,7 @@ NSSurfacePropEntity::NSSurfacePropEntity(void) vector NSSurfacePropEntity::GetEyePos(void) { - if (HasFlags(FL_FAKESPEC)) { + if (HasVFlags(VFL_FAKESPEC)) { return (origin); } @@ -72,6 +72,12 @@ NSSurfacePropEntity::Spawned(void) #endif } +bool +NSSurfacePropEntity::IsOnFire(void) +{ + return (effects & EF_ONFIRE) ? true : false; +} + /* networking */ #ifdef SERVER void @@ -92,10 +98,64 @@ NSSurfacePropEntity::IsAlive(void) return (health > 0) ? true : false; } -void -NSSurfacePropEntity::SetCanBleed(bool bleedValue) +bool +NSSurfacePropEntity:: IsVulnerable(void) { - iBleeds = bleedValue; + return m_bTakesDamage; +} + +void +NSSurfacePropEntity::EnableBleeding(void) +{ + iBleeds = true; +} + +void +NSSurfacePropEntity::DisableBleeding(void) +{ + iBleeds = false; +} + +void +NSSurfacePropEntity::EnableAimAssist(void) +{ + m_bAutoAim = true; + _UpdateTakedamage(); +} + +void +NSSurfacePropEntity::DisableAimAssist(void) +{ + m_bAutoAim = false; + _UpdateTakedamage(); +} + +void +NSSurfacePropEntity::MakeVulnerable(void) +{ + m_bTakesDamage = true; + _UpdateTakedamage(); +} + +void +NSSurfacePropEntity::MakeInvulnerable(void) +{ + m_bTakesDamage = false; + _UpdateTakedamage(); +} + +void +NSSurfacePropEntity::_UpdateTakedamage(void) +{ + if (m_bTakesDamage) { + takedamage = DAMAGE_NO; + } else { + if (m_bAutoAim) { + takedamage = DAMAGE_AIM; + } else { + takedamage = DAMAGE_YES; + } + } } bool @@ -182,10 +242,10 @@ void NSSurfacePropEntity::ParentUpdate(void) { /* TODO: Move out */ - if (flags & FL_ONFIRE) { + if (IsOnFire()) { if (m_flBurnNext < time) { if (time > m_flBurnTime) { - flags &= ~FL_ONFIRE; + Extinguish(); } Damage_Apply(this, m_eBurner, 5, m_iBurnWeapon, DMG_BURN | DMG_SKIP_ARMOR); @@ -193,14 +253,14 @@ NSSurfacePropEntity::ParentUpdate(void) } } - NSRenderableEntity::ParentUpdate(); + super::ParentUpdate(); } /* Burning, fire, flames, etc. */ void NSSurfacePropEntity::Ignite(entity attacker, float flLifetime, int iWeapon) { - flags |= FL_ONFIRE; + effects |= EF_ONFIRE; m_eBurner = attacker; m_iBurnWeapon = iWeapon; m_flBurnTime = time + flLifetime; @@ -214,18 +274,12 @@ NSSurfacePropEntity::Ignite(entity attacker, float flLifetime, int iWeapon) void NSSurfacePropEntity::Extinguish(void) { - flags &= ~FL_ONFIRE; + effects &= ~EF_ONFIRE; m_eBurner = __NULL__; m_iBurnWeapon = m_flBurnTime = 0; } -bool -NSSurfacePropEntity::IsOnFire(void) -{ - return (flags & FL_ONFIRE) ? true : false; -} - void NSSurfacePropEntity::Respawn(void) { @@ -644,7 +698,7 @@ NSSurfacePropEntity::ReceiveEntity(float flNew, float flChanged) void NSSurfacePropEntity::RenderFire(void) { - if (flags & FL_ONFIRE) { + if (IsOnFire()) { vector someorg; if (m_flBurnNext < time) { diff --git a/src/shared/NSTalkMonster.qc b/src/shared/NSTalkMonster.qc index ca753764..3e1ad74a 100644 --- a/src/shared/NSTalkMonster.qc +++ b/src/shared/NSTalkMonster.qc @@ -316,17 +316,18 @@ NSTalkMonster::Speak(string sentence) void NSTalkMonster::TalkPlayerGreet(void) { - if (HasSpawnFlags(MSF_GAG)) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; - - if (m_iSequenceState != SEQUENCESTATE_NONE) + } + if (m_flNextSentence > time) { return; - - if (m_flNextSentence > time) + } + if (m_bGagged) { return; - - if (m_iFlags & MONSTER_METPLAYER) + } + if (m_iFlags & MONSTER_METPLAYER) { return; + } for (entity p = world; (p = find(p, ::classname, "player"));) { /* Find players in a specific radius */ @@ -347,17 +348,17 @@ NSTalkMonster::TalkPlayerGreet(void) void NSTalkMonster::TalkPlayerIdle(void) { - if (HasSpawnFlags(MSF_GAG)) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; - - if (m_iSequenceState != SEQUENCESTATE_NONE) + } + if (m_flNextSentence > time) { return; - - if (m_flNextSentence > time) + } + if (m_bGagged) { return; + } for (entity p = world; (p = find(p, ::classname, "player"));) { - if (IsFriend(p.m_iAlliance) == false) { continue; } @@ -366,9 +367,11 @@ NSTalkMonster::TalkPlayerIdle(void) if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) { /* If we can't physically see him, don't do anything */ traceline(origin, p.origin, FALSE, this); + if (trace_ent != p) { continue; } + Sentence(m_talkPlayerIdle); m_flNextSentence = time + 10.0; break; @@ -379,14 +382,15 @@ NSTalkMonster::TalkPlayerIdle(void) void NSTalkMonster::TalkPlayerAsk(void) { - if (HasSpawnFlags(MSF_GAG)) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; - - if (m_iSequenceState != SEQUENCESTATE_NONE) + } + if (m_flNextSentence > time) { return; - - if (m_flNextSentence > time) + } + if (m_bGagged) { return; + } for (entity p = world; (p = find(p, ::classname, "player"));) { /* Find players in a specific radius */ @@ -406,14 +410,15 @@ NSTalkMonster::TalkPlayerAsk(void) void NSTalkMonster::TalkPlayerWounded1(void) { - if (HasSpawnFlags(MSF_GAG)) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; - - if (m_iSequenceState != SEQUENCESTATE_NONE) + } + if (m_flNextSentence > time) { return; - - if (m_flNextSentence > time) + } + if (m_bGagged) { return; + } if (base_health < health) return; @@ -435,14 +440,15 @@ NSTalkMonster::TalkPlayerWounded1(void) void NSTalkMonster::TalkPlayerWounded2(void) { - if (HasSpawnFlags(MSF_GAG)) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; - - if (m_iSequenceState != SEQUENCESTATE_NONE) + } + if (m_flNextSentence > time) { return; - - if (m_flNextSentence > time) + } + if (m_bGagged) { return; + } if ((base_health / 2) < health) return; @@ -465,14 +471,15 @@ NSTalkMonster::TalkPlayerWounded2(void) void NSTalkMonster::TalkPlayerWounded3(void) { - if (HasSpawnFlags(MSF_GAG)) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; - - if (m_iSequenceState != SEQUENCESTATE_NONE) + } + if (m_flNextSentence > time) { return; - - if (m_flNextSentence > time) + } + if (m_bGagged) { return; + } for (entity p = world; (p = find(p, ::classname, "player"));) { /* Find players in a specific radius */ @@ -492,11 +499,12 @@ NSTalkMonster::TalkPlayerWounded3(void) void NSTalkMonster::TalkPanic(void) { - if (HasSpawnFlags(MSF_GAG)) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; - - if (m_iSequenceState != SEQUENCESTATE_NONE) + } + if (m_bGagged) { return; + } Sentence(m_talkPanic); m_flNextSentence = time + 2.5; @@ -506,8 +514,12 @@ NSTalkMonster::TalkPanic(void) void NSTalkMonster::TalkUnfollow(void) { - if (m_iSequenceState != SEQUENCESTATE_NONE) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; + } + if (m_bGagged) { + return; + } Sentence(m_talkUnfollow); m_flNextSentence = time + 10.0; @@ -516,8 +528,12 @@ NSTalkMonster::TalkUnfollow(void) void NSTalkMonster::TalkFollow(void) { - if (m_iSequenceState != SEQUENCESTATE_NONE) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; + } + if (m_bGagged) { + return; + } Sentence(m_talkFollow); m_flNextSentence = time + 10.0; @@ -526,8 +542,12 @@ NSTalkMonster::TalkFollow(void) void NSTalkMonster::TalkStopFollow(void) { - if (m_iSequenceState != SEQUENCESTATE_NONE) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; + } + if (m_bGagged) { + return; + } Sentence(m_talkStopFollow); m_flNextSentence = time + 10.0; @@ -536,8 +556,12 @@ NSTalkMonster::TalkStopFollow(void) void NSTalkMonster::TalkDenyFollow(void) { - if (m_iSequenceState != SEQUENCESTATE_NONE) + if (m_iSequenceState != SEQUENCESTATE_NONE) { return; + } + if (m_bGagged) { + return; + } Sentence(m_talkDenyFollow); m_flNextSentence = time + 10.0; @@ -569,7 +593,7 @@ NSTalkMonster::FollowPlayer(void) float flPlayerDist; input_angles = vectoangles(m_eFollowingChain.origin - origin); input_angles[0] = 0; - input_angles[1] = Math_FixDelta(input_angles[1]); + input_angles[1] = fixAngleDelta(input_angles[1]); input_angles[2] = 0; _LerpTurnToYaw(input_angles); @@ -636,7 +660,7 @@ NSTalkMonster::FollowPlayer(void) } else { input_angles = vectoangles(m_vecLastUserPos - origin); input_angles[0] = 0; - input_angles[1] = Math_FixDelta(input_angles[1]); + input_angles[1] = fixAngleDelta(input_angles[1]); input_angles[2] = 0; _LerpTurnToYaw(input_angles); } @@ -687,7 +711,7 @@ NSTalkMonster::PanicFrame(void) } } - angles[1] = Math_FixDelta(bestYaw + random(-25, 25)); + angles[1] = fixAngleDelta(bestYaw + random(-25, 25)); input_angles[1] = angles[1]; v_angle[1] = angles[1]; m_flTraceTime = time + 0.5f + random(); @@ -1073,7 +1097,41 @@ NSTalkMonster::predraw(void) RenderAxialScale(); +#if 0 + /* has the current top frame changed? */ + if (frame != frame2) { + /* we're done lerping */ + if (lerpfrac <= 0.0f) { + frame2 = frame; + lerpfrac = 0.0f; + } + + lerpfrac = max(0.0, lerpfrac - (frametime * 5.0)); + } else { + /* make sure we're set up for next lerp */ + lerpfrac = 1.0f; + frame2time = frame1time; + } + + /* are we inside of an interpolation? */ + if (baseframe != baseframe2) { + /* we're done lerping */ + if (baselerpfrac <= 0.0f) { + baseframe2 = baseframe; + baselerpfrac = 0.0f; + } + + baselerpfrac = max(0.0, baselerpfrac - (frametime * 5.0)); + //printf("baselerpfrac: %f\n", baselerpfrac); + } else { + /* make sure we're set up for next lerp */ + baselerpfrac = 1.0f; + baseframe2time = baseframe1time; + } +#endif + addentity(this); + _RenderDebugViewCone(); RenderGLQuakeShadow(); diff --git a/src/shared/NSTrigger.qc b/src/shared/NSTrigger.qc index 04597818..204e8c89 100644 --- a/src/shared/NSTrigger.qc +++ b/src/shared/NSTrigger.qc @@ -23,7 +23,7 @@ NSTrigger::NSTrigger(void) #ifdef SERVER m_oldstrTarget = __NULL__; m_strGlobalState = __NULL__; - m_strKillTarget = __NULL__; + m_strKillTarget = ""; m_strMessage = __NULL__; m_strMaster = __NULL__; m_iUseType = 0i; @@ -62,7 +62,7 @@ NSTrigger::CanBeTriggeredBy(entity testEnt) return false; if (!(spawnflags & TOUCHFILTER_FRIENDLIES) && (testEnt.flags & FL_MONSTER) && (testEnt.m_iAlliance == 0)) return false; - if (!(spawnflags & TOUCHFILTER_CLIENTSINVEHICLES) && (testEnt.flags & FL_CLIENT) && (testEnt.flags & FL_INVEHICLE)) + if (!(spawnflags & TOUCHFILTER_CLIENTSINVEHICLES) && (testEnt.flags & FL_CLIENT) && (testEnt.vv_flags & VFL_INVEHICLE)) return false; /* @@ -108,7 +108,7 @@ NSTrigger::UseTargets(entity act, int state, float triggerDelay) eTimer.nextthink = time + triggerDelay; eTimer.health = state; /* ugly */ - if (m_strKillTarget) { + if (m_strKillTarget != "") { EntLog("Will kill %S before that happens.", m_strKillTarget); } eTimer.m_strKillTarget = m_strKillTarget; @@ -131,7 +131,7 @@ NSTrigger::UseTargets(entity act, int state, float triggerDelay) } } - if (m_strKillTarget && m_strKillTarget != "") { + if (m_strKillTarget != "") { NSEntity eKill = (NSEntity)find(world, ::targetname, m_strKillTarget); EntLog("Killtargeting %S", m_strKillTarget); @@ -250,6 +250,10 @@ NSTrigger::Save(float handle) SaveBool(handle, "m_bStartDisabled", m_bStartDisabled); SaveBool(handle, "m_bEnabled", m_bEnabled); SaveBool(handle, "m_bIsModern", m_bIsModern); + SaveFloat(handle, "m_flTouchTime", m_flTouchTime); + SaveBool(handle, "m_beingTouched", m_beingTouched); + SaveEntity(handle, "m_eTouchLast", m_eTouchLast); + SaveFloat(handle, "team_no", team_no); } void NSTrigger::Restore(string strKey, string strValue) @@ -294,6 +298,18 @@ NSTrigger::Restore(string strKey, string strValue) case "m_bIsModern": m_bIsModern = ReadBool(strValue); break; + case "m_flTouchTime": + m_flTouchTime = ReadFloat(strValue); + break; + case "m_beingTouched": + m_beingTouched = ReadBool(strValue); + break; + case "m_eTouchLast": + m_eTouchLast = ReadEntity(strValue); + break; + case "team_no": + team_no = ReadFloat(strValue); + break; default: super::Restore(strKey, strValue); } diff --git a/src/shared/NSVehicle.h b/src/shared/NSVehicle.h index 2347f599..2dc425f4 100644 --- a/src/shared/NSVehicle.h +++ b/src/shared/NSVehicle.h @@ -32,9 +32,9 @@ private: int m_iVehicleFlags; int m_iMoveButtons; vector m_vecMoveValues; - entity m_eDriver; - entity m_eDriver_net; - entity m_eDriverLast; + NSEntity m_eDriver; + NSEntity m_eDriver_net; + NSEntity m_eDriverLast; vector m_vecPlayerPos; vector m_vecExitPos; diff --git a/src/shared/NSVehicle.qc b/src/shared/NSVehicle.qc index 72879bfa..2e0fce43 100644 --- a/src/shared/NSVehicle.qc +++ b/src/shared/NSVehicle.qc @@ -54,10 +54,10 @@ NSVehicle::Restore(string strKey, string strValue) m_vecMoveValues = ReadVector(strValue); break; case "m_eDriver": - m_eDriver = ReadEntity(strValue); + m_eDriver = (NSEntity)ReadEntity(strValue); break; case "m_eDriverLast": - m_eDriverLast = ReadEntity(strValue); + m_eDriverLast = (NSEntity)ReadEntity(strValue); break; case "m_vecPlayerPos": m_vecPlayerPos = ReadVector(strValue); @@ -125,7 +125,7 @@ NSVehicle::DriverRelink(void) m_eDriver = __NULL__; else { NSClientPlayer pl; - m_eDriver = findentity(world, ::entnum, driver_entnum); + m_eDriver = (NSEntity)findentity(world, ::entnum, driver_entnum); pl = (NSClientPlayer)m_eDriver; pl.vehicle = this; } @@ -215,7 +215,7 @@ NSVehicle::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) @@ -302,10 +302,6 @@ NSVehicle::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]); - SetSendFlags(VEHFL_CHANGED_ANGLES); } if (ATTR_CHANGED(velocity)) @@ -400,7 +396,7 @@ void NSVehicle::PlayerUpdateFlags(void) { if (m_iVehicleFlags & VHF_FROZEN) - m_eDriver.flags |= FL_FROZEN; + m_eDriver.vv_flags |= VFL_FROZEN; /*if (m_iVehicleFlags & VHF_NOATTACK) m_eDriver.flags |= FL_NOATTACK;*/ @@ -442,10 +438,10 @@ NSVehicle::PlayerEnter(NSClientPlayer pl) m_vecExitPos = m_vecPlayerPos; owner = pl; //pl.movetype = MOVETYPE_NOCLIP; - m_eDriver = (entity)pl; + m_eDriver = (NSEntity)pl; m_eDriverLast = m_eDriver; pl.vehicle = this; - pl.flags |= FL_INVEHICLE; + pl.vv_flags |= VFL_INVEHICLE; EntLog("Player %S entered this vehicle.", pl.GetInfoKey("name")); } @@ -458,12 +454,12 @@ NSVehicle::PlayerLeave(NSClientPlayer pl) EntLog("Player %S exits this vehicle.", pl.GetInfoKey("name")); owner = __NULL__; - pl.flags &= ~FL_INVEHICLE; + pl.vv_flags &= ~VFL_INVEHICLE; pl.velocity = g_vec_null; setorigin_safe(pl, pl.origin); if (m_iVehicleFlags & VHF_FROZEN) - pl.flags &= ~FL_FROZEN; + pl.vv_flags &= ~VFL_FROZEN; /*if (m_iVehicleFlags & VHF_NOATTACK) pl.flags &= ~FL_NOATTACK;*/ diff --git a/src/shared/ammo.h b/src/shared/ammo.h new file mode 100644 index 00000000..5ea1150f --- /dev/null +++ b/src/shared/ammo.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016-2024 Vera Visions LLC. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/*! @file ammo.h + @brief Ammo Handling Helper Functions. + + Helper functions for various ammo operations. + This header can be included in other libraries and projects to help + deal with these sorts of issues. + It is usually included by default in a library project. + If you want to include this file into your own progs, you + can include `math.h` from `src/shared/`. +*/ + +/** Returns the name of the specified ammo type. Returns __NULL__ when invalid. */ +string ammoNameForNum(int); +/** Returns the ammo id of a given name of ammo. Return -1 when invalid. */ +int ammoNumForName(string); + diff --git a/src/shared/decalgroups.qc b/src/shared/decalgroups.qc index 95385ff8..8891f20a 100644 --- a/src/shared/decalgroups.qc +++ b/src/shared/decalgroups.qc @@ -155,14 +155,6 @@ DecalGroups_Init(void) fclose(fh); -#if 0 -#ifdef CLIENT - for (int i = 0; i < g_decalgroup_count; i++) { - print(sprintf("%i (members: %i) %s\n", i, g_decalgroup[i].members, g_decalgroup[i].materials)); - } -#endif -#endif - NSLog("...decal groups initialized with %i entries.", g_decalgroup_count); InitEnd(); } diff --git a/src/shared/defs.h b/src/shared/defs.h index f8e0032e..78a9c213 100644 --- a/src/shared/defs.h +++ b/src/shared/defs.h @@ -71,6 +71,8 @@ string __fullspawndata; #include "global.h" #include "cloader.h" #include "sound.h" +#include "effects.h" +#include "math.h" #ifdef CLIENT #include "../gs-entbase/client/defs.h" @@ -113,12 +115,10 @@ string __fullspawndata; #include "materials.h" #include "damage.h" #include "flags.h" -#include "effects.h" #include "entities.h" #include "events.h" #include "flags.h" #include "hitmesh.h" -#include "math.h" #include "pmove.h" #include "memory.h" #include "platform.h" @@ -126,7 +126,6 @@ string __fullspawndata; #include "surfaceproperties.h" #include "decalgroups.h" #include "colors.h" -#include "weapons.h" #include "motd.h" #include "util.h" @@ -149,13 +148,22 @@ const vector VEC_CHULL_MAX = [16,16,18]; // Actually used by input_button etc. #define INPUT_BUTTON0 0x00000001 /* attack 1*/ #define INPUT_BUTTON2 0x00000002 /* jumping */ -#define INPUT_BUTTON3 0x00000004 /* attack 2 */ +#define INPUT_BUTTON3 0x00000004 /* prone */ #define INPUT_BUTTON4 0x00000008 /* reload */ -#define INPUT_BUTTON5 0x00000010 /* use button */ -#define INPUT_BUTTON6 0x00000020 /* reserved */ +#define INPUT_BUTTON5 0x00000010 /* secondary */ +#define INPUT_BUTTON6 0x00000020 /* use */ #define INPUT_BUTTON7 0x00000040 /* reserved */ #define INPUT_BUTTON8 0x00000080 /* crouching */ +#define INPUT_PRIMARY INPUT_BUTTON0 +#define INPUT_JUMP INPUT_BUTTON2 +#define INPUT_PRONE INPUT_BUTTON3 +#define INPUT_RELOAD INPUT_BUTTON4 +#define INPUT_SECONDARY INPUT_BUTTON6 +#define INPUT_USE INPUT_BUTTON5 /* This can NEVER change. Engine hard-coded. */ +#define INPUT_SPRINT INPUT_BUTTON7 +#define INPUT_CROUCH INPUT_BUTTON8 + /* sendflags */ #define UPDATE_ALL 16777215 @@ -518,3 +526,85 @@ FileExists(string filePath) return true; } + +void +DebugBox(vector absPos, vector minSize, vector maxSize, vector boxColor, float boxAlpha) +{ + vector a, b, c, d; + vector w, x, y, z; + + a[0] = absPos[0] + minSize[0]; + a[1] = absPos[1] + maxSize[1]; + + b[0] = absPos[0] + maxSize[0]; + b[1] = absPos[1] + maxSize[1]; + + c[0] = absPos[0] + maxSize[0]; + c[1] = absPos[1] + minSize[1]; + + d[0] = absPos[0] + minSize[0]; + d[1] = absPos[1] + minSize[1]; + + a[2] = absPos[2] + maxSize[2]; + c[2] = absPos[2] + maxSize[2]; + d[2] = absPos[2] + maxSize[2]; + b[2] = absPos[2] + maxSize[2]; + + w = a; + x = b; + y = c; + z = d; + + w[2] = absPos[2] + minSize[2]; + x[2] = absPos[2] + minSize[2]; + y[2] = absPos[2] + minSize[2]; + z[2] = absPos[2] + minSize[2]; + + /* top */ + R_BeginPolygon("", 0, 0); + R_PolygonVertex(a, [1,1], boxColor, boxAlpha); + R_PolygonVertex(b, [0,1], boxColor, boxAlpha); + R_PolygonVertex(c, [0,0], boxColor, boxAlpha); + R_PolygonVertex(d, [1,0], boxColor, boxAlpha); + R_EndPolygon(); + + /* front */ + R_BeginPolygon("", 0, 0); + R_PolygonVertex(d, [1,1], boxColor * 0.9f, boxAlpha); + R_PolygonVertex(c, [0,1], boxColor * 0.9f, boxAlpha); + R_PolygonVertex(y, [0,0], boxColor * 0.9f, boxAlpha); + R_PolygonVertex(z, [1,0], boxColor * 0.9f, boxAlpha); + R_EndPolygon(); + + /* back */ + R_BeginPolygon("", 0, 0); + R_PolygonVertex(w, [1,1], boxColor * 0.9f, boxAlpha); + R_PolygonVertex(x, [0,1], boxColor * 0.9f, boxAlpha); + R_PolygonVertex(b, [0,0], boxColor * 0.9f, boxAlpha); + R_PolygonVertex(a, [1,0], boxColor * 0.9f, boxAlpha); + R_EndPolygon(); + + /* left */ + R_BeginPolygon("", 0, 0); + R_PolygonVertex(a, [1,1], boxColor * 0.8f, boxAlpha); + R_PolygonVertex(d, [0,1], boxColor * 0.8f, boxAlpha); + R_PolygonVertex(z, [0,0], boxColor * 0.8f, boxAlpha); + R_PolygonVertex(w, [1,0], boxColor * 0.8f, boxAlpha); + R_EndPolygon(); + + /* right */ + R_BeginPolygon("", 0, 0); + R_PolygonVertex(c, [1,1], boxColor * 0.8f, boxAlpha); + R_PolygonVertex(b, [0,1], boxColor * 0.8f, boxAlpha); + R_PolygonVertex(x, [0,0], boxColor * 0.8f, boxAlpha); + R_PolygonVertex(y, [1,0], boxColor * 0.8f, boxAlpha); + R_EndPolygon(); + + /* bottom */ + R_BeginPolygon("", 0, 0); + R_PolygonVertex(z, [1,1], boxColor, boxAlpha); + R_PolygonVertex(y, [0,1], boxColor, boxAlpha); + R_PolygonVertex(x, [0,0], boxColor, boxAlpha); + R_PolygonVertex(w, [1,0], boxColor, boxAlpha); + R_EndPolygon(); +} diff --git a/src/shared/effects.h b/src/shared/effects.h index 3593a044..900c8cd0 100644 --- a/src/shared/effects.h +++ b/src/shared/effects.h @@ -15,27 +15,30 @@ */ /* engine reserved */ -#define EF_BRIGHTFIELD (1<<0) /**< Cast a bright, starry field volume. */ -#define EF_MUZZLEFLASH (1<<1) /**< Cast a medium sized dynamic light. */ -#define EF_BRIGHTLIGHT (1<<2) /**< Cast a large sized dynamic light. */ -#define EF_DIMLIGHT (1<<3) /**< Cast a small sized dynamic light. */ -#define EF_NODRAW (1<<4) /**< Skip rendering of the entity. Also known as EF_FLAG1 in QW */ -#define EF_ADDITIVE (1<<5) /**< Render the entity additively. Also known as EF_FLAG2 in QW */ -#define EF_BLUE (1<<6) /**< Cast a blue dynamic light. */ -#define EF_RED (1<<7) /**< Cast a red dynamic light. */ -#define EF_UNUSED1 (1<<8) /**< Unused. */ -#define EF_FULLBRIGHT (1<<9) /**< Render entity without lighting. */ -#define EF_UNUSED2 (1<<10) /**< Unused. */ -#define EF_UNUSED3 (1<<11) /**< Unused. */ -#define EF_NOSHADOW (1<<12) /**< Entity won't cast a shadow. */ -#define EF_NODEPTHTEST (1<<13) /**< Entity renders through walls. */ -#define EF_UNUSED4 (1<<14) /**< Unused. */ -#define EF_UNUSED5 (1<<15) /**< Unused. */ -#define EF_UNUSED6 (1<<16) /**< Unused. */ -#define EF_UNUSED7 (1<<17) /**< Unused. */ -#define EF_GREEN (1<<18) /**< Cast a green dynamic light. */ -#define EF_UNUSED8 (1<<19) /**< Unused. */ -#define EF_UNUSED9 (1<<20) /**< Unused. */ -#define EF_UNUSED10 (1<<21) /**< Unused. */ -#define EF_UNUSED11 (1<<22) /**< Unused. */ -#define EF_UNUSED12 (1<<23) /**< Unused. */ \ No newline at end of file +typedef enum +{ + EF_BRIGHTFIELD = (1<<0), /**< Cast a bright, starry field volume. */ + EF_MUZZLEFLASH = (1<<1), /**< Cast a medium sized dynamic light. */ + EF_BRIGHTLIGHT = (1<<2), /**< Cast a large sized dynamic light. */ + EF_DIMLIGHT = (1<<3), /**< Cast a small sized dynamic light. */ + EF_NODRAW = (1<<4), /**< Skip rendering of the entity. Also known as EF_FLAG1 in QW */ + EF_ADDITIVE = (1<<5), /**< Render the entity additively. Also known as EF_FLAG2 in QW */ + EF_BLUE = (1<<6), /**< Cast a blue dynamic light. */ + EF_RED = (1<<7), /**< Cast a red dynamic light. */ + EF_UNUSED1 = (1<<8), /**< Unused. */ + EF_FULLBRIGHT = (1<<9), /**< Render entity without lighting. */ + EF_UNUSED2 = (1<<10), /**< Unused. */ + EF_UNUSED3 = (1<<11), /**< Unused. */ + EF_NOSHADOW = (1<<12), /**< Entity won't cast a shadow. */ + EF_NODEPTHTEST = (1<<13), /**< Entity renders through walls. */ + EF_UNUSED4 = (1<<14), /**< Unused. */ + EF_UNUSED5 = (1<<15), /**< Unused. */ + EF_UNUSED6 = (1<<16), /**< Unused. */ + EF_UNUSED7 = (1<<17), /**< Unused. */ + EF_GREEN = (1<<18), /**< Cast a green dynamic light. */ + EF_UNUSED8 = (1<<19), /**< Unused. */ + EF_UNUSED9 = (1<<20), /**< Unused. */ + EF_UNUSED10 = (1<<21), /**< Unused. */ + EF_UNUSED11 = (1<<22), /**< Unused. */ + EF_ONFIRE = (1<<23) /**< Unused. */ +} effects_t; \ No newline at end of file diff --git a/src/shared/entities.h b/src/shared/entities.h index b2e766a0..7b5ed502 100644 --- a/src/shared/entities.h +++ b/src/shared/entities.h @@ -19,6 +19,7 @@ typedef enum { ENT_NONE = 0, /**< invalid, but reserved. */ ENT_ENTITY, /**< of type NSEntity */ + ENT_PMOVEVARS, /** of type NSPMoveVars */ ENT_ENTITYRENDERABLE, /**< of type NSRenderableEntity */ ENT_ENTITYPROJECTILE, /**< of type NSProjectile */ ENT_SURFPROP, /**< of type NSSurfacePropEntity */ diff --git a/src/shared/flags.h b/src/shared/flags.h index 72abc95f..153d9117 100644 --- a/src/shared/flags.h +++ b/src/shared/flags.h @@ -32,12 +32,16 @@ #define FLQW_LAGGEDMOVE (1<<16) /**< Entity will move with lag compenstation. */ /* nuclide */ -#define FL_ONLADDER (1<<13) /**< Entity is attached to a ladder. */ -#define FL_CROUCHING (1<<17) /**< Entity is crouching. */ -#define FL_INVEHICLE (1<<18) /**< Entity is inside a vehicle. */ -#define FL_FROZEN (1<<19) /**< Entity is not allowed to move. */ -#define FL_USE_RELEASED (1<<20) /**< Entity has release the +use button. */ -#define FL_FAKESPEC (1<<21) /**< Entity is a fake spectator. */ -#define FL_ONUSABLE (1<<22) /**< Entity is able to +use a thing. */ -#define FL_ONFIRE (1<<23) /**< Entity is on fire. */ -#define FL_GOALITEM (1<<15) /**< Entity is a goal-item. */ +.float vv_flags; +#define VFL_PRONE (1<<0) /**< Entity is prone. */ +#define VFL_ONLADDER (1<<1) /**< Entity is attached to a ladder. */ +#define VFL_CROUCHING (1<<2) /**< Entity is crouching. */ +#define VFL_INVEHICLE (1<<3) /**< Entity is inside a vehicle. */ +#define VFL_FROZEN (1<<4) /**< Entity is not allowed to move. */ +#define VFL_USE_RELEASED (1<<5) /**< Entity has release the +use button. */ +#define VFL_FAKESPEC (1<<6) /**< Entity is a fake spectator. */ +#define VFL_ONUSABLE (1<<7) /**< Entity is able to +use a thing. */ +#define VFL_SPRINTING (1<<8) /**< Entity is on fire. */ +#define VFL_GOALITEM (1<<9) /**< Entity is a goal-item. */ +#define VFL_NOATTACK (1<<10) /**< Entity is not allowed to fire. */ + diff --git a/src/shared/include.src b/src/shared/include.src index 9d82ac00..d6f8c76c 100644 --- a/src/shared/include.src +++ b/src/shared/include.src @@ -11,6 +11,7 @@ NSPhysicsConstraint.qc NSPhysicsEntity.qc NSBrushTrigger.qc NSPointTrigger.qc +pmove.qc NSVehicle.qc NSNavAI.qc NSMonster.qc @@ -21,14 +22,11 @@ NSSpawnPoint.qc NSItem.qc NSPortal.qc NSDebris.qc - NSClient.qc NSClientSpectator.qc -pmove.qc pmove_custom.qc cloader.qc sound.qc -math.qc NSClientPlayer.qc player_pmove.qc propdata.qc @@ -41,5 +39,6 @@ util.qc weapons.qc motd.qc +weapon_common.qc ../xr/include.src #endlist diff --git a/src/shared/math.h b/src/shared/math.h index 9dea56cf..0ee895c7 100644 --- a/src/shared/math.h +++ b/src/shared/math.h @@ -14,15 +14,258 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/*! @file math.h + @brief Vector Math Helper Functions + + Helper functions for various mathematical operations. + This header can be included in other libraries and projects to help + deal with these sorts of issues. + It is usually included by default in a library project. + If you want to include this file into your own progs, you + can include `math.h` from `src/shared/`. +*/ + +/** Approximation of Pi. */ #define MATH_PI 3.1415926 +noref const vector g_vec_null = [0.0f, 0.0f, 0.0f]; -float Math_LerpAngle(float fStart, float fEnd, float fAmount); -float Math_Lerp(float fA, float fB, float fPercent); -float Math_FixDelta(float fDelta); -vector Math_FixDeltaVector(vector); -vector Math_Reflect(vector v1, vector v2); -vector Math_RandomVector(float flyup); -vector Math_RotateAroundPivot(vector pos, vector pivot, float degr); -vector Math_AngleDiff(vector from, vector to); +#ifdef MENU -vector hsv2rgb(float h, float s, float v); +vector(vector fwd, optional vector up) vectoangles2 = #11; +void(vector angle) rotatevectorsbyangle = #0; + +#define vectoangles vectoangles2 + +vector v_forward; +vector v_up; +vector v_right; +void makevectors( vector angles ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[1] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[0] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[2] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + v_forward[0] = cp*cy; + v_forward[1] = cp*sy; + v_forward[2] = -sp; + + v_right[0] = (-1*sr*sp*cy+-1*cr*-sy); + v_right[1] = (-1*sr*sp*sy+-1*cr*cy); + v_right[2] = -1*sr*cp; + + v_up[0] = (cr*sp*cy+-sr*-sy); + v_up[1] = (cr*sp*sy+-sr*cy); + v_up[2] = cr*cp; +} +#endif + + +/** Euler-angle lerping function that accounts for negative degrees. + +@param startValue is the value closest when lerpAmount is 0.0 +@param endValue is the value closest when lerpAmount is 1.0 +@param lerpAmount is the lerp value. Between 0.0 and 1.0 is common. +@return Interpolated angl between start and end. */ +float +lerpAngle(float startAngle, float endAngle, float lerpAmount) +{ + float shortest_angle = ((((endAngle - startAngle) % 360.0f) + 540.0f) % 360.0f) - 180.0f; + return shortest_angle * lerpAmount; +} + +/** Linear lerp function. + +@param startValue is the value closest when lerpAmount is 0.0 +@param endValue is the value closest when lerpAmount is 1.0 +@param lerpAmount is the lerp value. Between 0.0 and 1.0 is common. +@return Interpolated value between start and end. */ +float +lerp(float startValue, float endValue, float lerpAmount) +{ + return (startValue * (1 - lerpAmount)) + (endValue * lerpAmount); +} + +/** Tecursive function that fixes an euler angle. + +@param angleValue is the angle value to 'fix'. +@return Angle value between -180 and +180. */ +float +fixAngleDelta(float angleValue) +{ + if (angleValue > 180) { + angleValue -= 360; + } else if (angleValue < -180) { + angleValue += 360; + } else { + return angleValue; + } + + return fixAngleDelta(angleValue); +} + + +/** Recursive function that fixes euler angles. + +@param inputAngle is the angle value to 'fix'. +@return Angle where pitch/yaw/roll are now between -180 and +180. */ +vector +fixAngle(vector inputAngle) +{ + inputAngle[0] = fixAngleDelta(inputAngle[0]); + inputAngle[1] = fixAngleDelta(inputAngle[1]); + inputAngle[2] = fixAngleDelta(inputAngle[2]); + return inputAngle; +} + +/** Takes a direction and a plane normal, returns a new trajectory. + +@param hitDirection is from where a trace/shot is aiming from. Usually a result from anglesToForward(). +@param planeNormal is the impact normal. Usually retrieved from a traceline() call updating the trace_plane_normal global. +@return New direction, calculated from hitDirection hitting planeNormal. */ +vector +reflect(vector hitDirection, vector planeNormal) +{ + return hitDirection - 2 * dotproduct(hitDirection, planeNormal) * planeNormal; +} + +/** Calculates a random Vector, with every axis being a value between -1.0 and 1.0, unless flyUp is `true`. + +@param flyUp being `true` will result in the Z-axis never returning negative values. +@return Random output vector. */ +vector +randomVector(bool flyUp) +{ + vector tmp; + tmp[0] = random() - 0.5f; + tmp[1] = random() - 0.5f; + + if ( flyUp == true ) { + tmp[2] = random(); + } else { + tmp[2] = random() - 0.5f; + } + + return tmp * 2.0f; +} + +/** Takes a position and a pivot point and rotates point by N degrees around the pivot (YAW) + +@param pos is the points' current, absolute position. +@param pivot is the absolute position of the pivot point. +@param degr is the rotation amount in degrees. +@return Point in world-space that's been rotated. */ +vector +rotateAroundPoint(vector pos, vector pivot, float degr) +{ + vector new = pos; + new[0] = pivot[0] + (pos[0] - pivot[0]) * cos(degr) - (pos[1] - pivot[1]) * sin(degr); + new[1] = pivot[1] + (pos[0] - pivot[0]) * sin(degr) + (pos[1] - pivot[1]) * cos(degr); + return new; +} + +/** Calculates the difference between two angles. + +@param angle1 is the first angle. +@param angle2 is the second angle. +@return The difference between angle1 and angle2 in euler angles. */ +vector +angleDifference(vector angle1, vector angle2) +{ + static float Math_AngleDiff_S(float from, float to) { + float angleDelta = from - to; + + if (angleDelta > 180) { + angleDelta -= 360; + } else if (angleDelta < -180) { + angleDelta += 360; + } + + return angleDelta; + } + + vector newAngle; + + /* clean up input angles */ + angle1 = fixAngle(angle1); + angle2 = fixAngle(angle2); + + newAngle[0] = Math_AngleDiff_S(angle1[0], angle2[0]); + newAngle[1] = Math_AngleDiff_S(angle1[1], angle2[1]); + newAngle[2] = Math_AngleDiff_S(angle1[2], angle2[2]); + return newAngle; +} + +/** Converts a Hue-Saturation-Value pair to an RGB vector. + +@param angle1 is the first angle. +@param angle2 is the second angle. +@return An RGB color, with values ranging between 0 and 255 on each channel. */ +vector +hsvToRGB(float h, float s, float v) +{ + float i,f,p,q,t; + vector col = [0,0,0]; + + h = max(0.0, min(360.0, h)); + s = max(0.0, min(100.0, s)); + v = max(0.0, min(100.0, v)); + + s /= 100; + v /= 100; + + if (s == 0) { + col[0] = col[1] = col[2] = rint(v*255); + return col; + } + + h /= 60; + i = floor(h); + f = h - i; + p = v * (1 - s); + q = v * (1 - s * f); + t = v * (1 - s * (1 - f)); + + switch (i) { + case 0: + col[0] = rint(255*v); + col[1] = rint(255*t); + col[2] = rint(255*p); + break; + case 1: + col[0] = rint(255*q); + col[1] = rint(255*v); + col[2] = rint(255*p); + break; + case 2: + col[0] = rint(255*p); + col[1] = rint(255*v); + col[2] = rint(255*t); + break; + case 3: + col[0] = rint(255*p); + col[1] = rint(255*q); + col[2] = rint(255*v); + break; + case 4: + col[0] = rint(255*t); + col[1] = rint(255*p); + col[2] = rint(255*v); + break; + default: + col[0] = rint(255*v); + col[1] = rint(255*p); + col[2] = rint(255*q); + } + return col; +} + +#include "math_vector.h" \ No newline at end of file diff --git a/src/shared/math.qc b/src/shared/math.qc deleted file mode 100644 index 0b301b4d..00000000 --- a/src/shared/math.qc +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2016-2024 Vera Visions LLC. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* lerping function that accounts for negative degrees */ -float -Math_LerpAngle(float fStart, float fEnd, float fAmount) -{ - float shortest_angle = ((((fEnd - fStart) % 360.0f) + 540.0f) % 360.0f) - 180.0f; - return shortest_angle * fAmount; -} - -/* linear lerp function */ -float -Math_Lerp(float fA, float fB, float fPercent) -{ - return (fA * (1 - fPercent)) + (fB * fPercent); -} - -/* recursive function that fixes an euler angle */ -float -Math_FixDelta(float fDelta) -{ - if (fDelta > 180) { - fDelta -= 360; - } else if (fDelta < -180) { - fDelta += 360; - } else { - return fDelta; - } - - return Math_FixDelta(fDelta); -} - -vector -Math_FixDeltaVector(vector in) -{ - in[0] = Math_FixDelta(in[0]); - in[1] = Math_FixDelta(in[1]); - in[2] = Math_FixDelta(in[2]); - return in; -} - -/* takes an impact angle and a plane normal, returns a new trajectory */ -vector -Math_Reflect(vector v1, vector v2) -{ - return v1 - 2 * dotproduct(v1, v2) * v2; -} - -/* returns a random vector, if the first paramete is true it'll make - * sure that vertical velocity is ALWAYS positive */ -vector -Math_RandomVector(float fFlyUp) -{ - vector tmp; - tmp[0] = random() - 0.5f; - tmp[1] = random() - 0.5f; - - if ( fFlyUp == TRUE ) { - tmp[2] = random(); - } else { - tmp[2] = random() - 0.5f; - } - - return tmp * 2.0f; -} - -/* takes a position and a pivot point and rotates point by X degrees around the pivot (YAW) */ -vector -Math_RotateAroundPivot(vector pos, vector pivot, float degr) -{ - vector new = pos; - new[0] = pivot[0] + (pos[0] - pivot[0]) * cos(degr) - (pos[1] - pivot[1]) * sin(degr); - new[1] = pivot[1] + (pos[0] - pivot[0]) * sin(degr) + (pos[1] - pivot[1]) * cos(degr); - return new; -} - - -vector -Math_AngleDiff(vector from, vector to) -{ - static float Math_AngleDiff_S(float from, float to) { - float angleDelta = from - to; - - if (angleDelta > 180) { - angleDelta -= 360; - } else if (angleDelta < -180) { - angleDelta += 360; - } - - return angleDelta; - } - - vector newAngle; - - /* clean up input angles */ - from = Math_FixDeltaVector(from); - to = Math_FixDeltaVector(to); - - newAngle[0] = Math_AngleDiff_S(from[0], to[0]); - newAngle[1] = Math_AngleDiff_S(from[1], to[1]); - newAngle[2] = Math_AngleDiff_S(from[2], to[2]); - return newAngle; -} - -vector hsv2rgb(float h, float s, float v) -{ - float i,f,p,q,t; - vector col = [0,0,0]; - - h = max(0.0, min(360.0, h)); - s = max(0.0, min(100.0, s)); - v = max(0.0, min(100.0, v)); - - s /= 100; - v /= 100; - - if (s == 0) { - col[0] = col[1] = col[2] = rint(v*255); - return col; - } - - h /= 60; - i = floor(h); - f = h - i; - p = v * (1 - s); - q = v * (1 - s * f); - t = v * (1 - s * (1 - f)); - - switch (i) { - case 0: - col[0] = rint(255*v); - col[1] = rint(255*t); - col[2] = rint(255*p); - break; - case 1: - col[0] = rint(255*q); - col[1] = rint(255*v); - col[2] = rint(255*p); - break; - case 2: - col[0] = rint(255*p); - col[1] = rint(255*v); - col[2] = rint(255*t); - break; - case 3: - col[0] = rint(255*p); - col[1] = rint(255*q); - col[2] = rint(255*v); - break; - case 4: - col[0] = rint(255*t); - col[1] = rint(255*p); - col[2] = rint(255*v); - break; - default: - col[0] = rint(255*v); - col[1] = rint(255*p); - col[2] = rint(255*q); - } - return col; -} diff --git a/src/shared/math_vector.h b/src/shared/math_vector.h new file mode 100644 index 00000000..556dcb8a --- /dev/null +++ b/src/shared/math_vector.h @@ -0,0 +1,279 @@ +/* + * 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. +*/ + +/*! @file math.h + @brief Math Helper Functions + + Helper functions for various mathematical operations. + This header can be included in other libraries and projects to help + deal with these sorts of issues. + It is usually included by default in a library project. + If you want to include this file into your own progs, you + can include `math.h` from `src/shared/`. +*/ + +var vector g_vectorCacheLast; +var vector g_vectorCacheForward; +var vector g_vectorCacheRight; +var vector g_vectorCacheUp; + +static void +anglesMake(vector angle) +{ + makevectors(angle); + g_vectorCacheLast = angle; + g_vectorCacheForward = v_forward; + g_vectorCacheRight = v_right; + g_vectorCacheUp = v_up; +} + +/** Calculates the forward vector of a set of euler-angles. +Will use a cached result to speed up queries. + +@param angle is an of euler-angle. +@return Directional vector pointing what the input angle is facing. */ +vector +anglesToForward(vector angle) +{ + if (angle == g_vectorCacheLast) { + return g_vectorCacheForward; + } + + anglesMake(angle); + return g_vectorCacheForward; +} + +/** Calculates the right vector of a set of euler-angles. +Will use a cached result to speed up queries. + +@param angle is an of euler-angle. +@return Directional vector pointing right of where the input angle is facing. */ +vector +anglesToRight(vector angle) +{ + if (angle == g_vectorCacheLast) { + return g_vectorCacheRight; + } + + anglesMake(angle); + return g_vectorCacheRight; +} + +/** Calculates the up vector of a set of euler-angles. +Will use a cached result to speed up queries. + +@param angle is an of euler-angle. +@return Directional vector pointing up of where the input angle is facing. */ +vector +anglesToUp(vector angle) +{ + if (angle == g_vectorCacheLast) { + return g_vectorCacheUp; + } + + anglesMake(angle); + return g_vectorCacheUp; +} + +/** Calculates the squared distance between two points. This is a lot faster than distance() calls, but does not reflect in-game units. Use it for any distance check you need to be fast. + +@param pointA is the first point. +@param pointB is the second point. +@return The distance between pointA and pointB in map units.*/ +float +distanceSquared(vector pointA, vector pointB) +{ + float diffX = pointA[0] - pointB[0]; + float diffY = pointA[1] - pointB[1]; + float diffZ = pointA[2] - pointB[2]; + return (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ); +} + +/** Calculates the distance between two points. + +@param pointA is the first point. +@param pointB is the second point. +@return The distance between pointA and pointB in map units.*/ +float +distance(vector pointA, vector pointB) +{ + return sqrt(distanceSquared(pointA, pointB)); +} + +/** Calculates the distance between two vectors, ignoring the height difference between them. + +@param pointA is the first point. +@param pointB is the second point. +@return The distance between pointA and pointB in map units.*/ +float +distance2D(vector pointA, vector pointB) +{ + float diffX = pointA[0] - pointB[0]; + float diffY = pointA[1] - pointB[1]; + return sqrt((diffX * diffX) + (diffY * diffY)); +} + +/** Figure out which point is the closest between two options. + +@param referencePoint is our shared point of reference. +@param pointA is the first point to check referencePoint against. +@param pointB is the second point to check referencePoint against. +@return Returns true if pointA is closer to referencePoint than pointB. */ +bool +closer(vector referencePoint, vector pointA, vector pointB) +{ + float distanceA = distanceSquared(referencePoint, pointA); + float distanceB = distanceSquared(referencePoint, pointA); + return (distanceA < distanceB) ? true : false; +} + +/** Calculates a set of angles from a given vector. + +@param toAngles is the vector to convert. +@return Euler-angles generated from the input. */ +vector +combineAngles(vector angleA, vector angleB) +{ + makevectors(angleA); + rotatevectorsbyangle(angleB); + return vectoangles(v_forward, v_up); +} + +/** Calculates accurate length of a given vector. + +@param target is the only input vector. +@return The accurate length of the input vector. */ +float +length(vector toCalculate) +{ + static vector lastInput = g_vec_null; + static float lastOutput = 0.0f; + + if (toCalculate == lastInput) { + return lastOutput; + } + + lastInput = toCalculate; + lastOutput = vlen(toCalculate); + return lastOutput; +} + +/** Calculates the length of a given vector using a dot product. + +@param target is the only input vector. +@return The approximate length of the input vector. */ +float +lengthSquared(vector target) +{ + return (target[0] * target[0]) + (target[1] * target[1]) + (target[2] * target[2]); +} + +/** Calculate the dot product of two vectors. + +@param vectorA is the first input. +@param vectorB is the second input. +@return The dot product of vectorA and vectorB. */ +float +vectorDot(vector vectorA, vector vectorB) +{ + return dotproduct(vectorA, vectorB); +} + +/** Calculates an interpolated (linear) point between two points. + +@param fromVector is the point closest when lerpFraction is `0.0`. +@param toVector is the point closest when lerpFraction is `1.0`. +@param lerpFraction controls the fraction of the way between the two points. +@return A point vector containing the interpolated result. */ +vector +vectorLerp(vector fromVector, vector toVector, float lerpFraction) +{ + static float vectorLerp_Lerp( float fA, float fB, float fPercent) { + return (fA * (1 - fPercent)) + (fB * fPercent); + } + + vector outputVector = g_vec_null; + outputVector[0] = vectorLerp_Lerp(fromVector[0], toVector[0], lerpFraction); + outputVector[1] = vectorLerp_Lerp(fromVector[1], toVector[1], lerpFraction); + outputVector[2] = vectorLerp_Lerp(fromVector[2], toVector[2], lerpFraction); + return outputVector; +} + +/** Calculates a normalized version of a given vector. + +@param toNormalize is the vector to convert. +@return Normalized vector generated from the input. */ +vector +vectorNormalize(vector toNormalize) +{ + static vector lastInput = g_vec_null; + static vector lastOutput = g_vec_null; + + if (toNormalize == lastInput) { + return lastOutput; + } + + lastInput = toNormalize; + lastOutput = normalize(toNormalize); + return lastOutput; +} + +/** Calculates a set of angles from a given vector. + +@param toAngles is the vector to convert. +@return Euler-angles generated from the input. */ +vector +vectorToAngles(vector toAngles) +{ + static vector lastInput = g_vec_null; + static vector lastOutput = g_vec_null; + + if (toAngles == lastInput) { + return lastOutput; + } + + lastInput = toAngles; + lastOutput = fixAngle(vectoangles(toAngles)); + return lastOutput; +} + +/** Calculates a set of angles from a given vector, with roll support. + +@return Euler-angles generated from the input. */ +vector +vectorToAnglesRoll(vector forwardDir, vector rollDir) +{ + static vector lastInput = g_vec_null; + static vector lastInput2 = g_vec_null; + static vector lastOutput = g_vec_null; + + if (forwardDir == lastInput && rollDir == lastInput2) { + return lastOutput; + } + + lastInput = forwardDir; + lastInput2 = rollDir; + lastOutput = fixAngle(vectoangles(forwardDir, rollDir)); + return lastOutput; +} + +vector +lerpAngleVector(vector inputAngle, vector endAngle, float lerpAmount) +{ + vector currentDir = anglesToForward(inputAngle); + vector desiredDir = anglesToForward(endAngle); + return vectorToAngles(vectorLerp(currentDir, desiredDir, lerpAmount)); +} \ No newline at end of file diff --git a/src/shared/player_pmove.qc b/src/shared/player_pmove.qc index bca52194..b82da71a 100644 --- a/src/shared/player_pmove.qc +++ b/src/shared/player_pmove.qc @@ -35,14 +35,6 @@ int saved_input_buttons; #define PHY_FALLDMG_TYPE 1 #endif -#ifndef PHY_JUMP_HEIGHT - #define PHY_JUMP_HEIGHT 240 -#endif - -#ifndef PHY_WATERJUMP_HEIGHT - #define PHY_WATERJUMP_HEIGHT 350 -#endif - #ifndef PHY_DIVESPEED_WATER #define PHY_DIVESPEED_WATER 100 #endif @@ -91,43 +83,162 @@ NSClientPlayer::Physics_Fall(float flDownforce) void NSClientPlayer::Physics_Crouch(void) { - bool crouchfix = false; + bool crouchFix = false; + vector testOrigin = origin; + vector testMins = g_vec_null; + vector testMaxs = g_vec_null; + bool stateChanged = false; if (GetMovetype() != MOVETYPE_WALK) return; - if (input_buttons & INPUT_BUTTON8) { - AddFlags(FL_CROUCHING); + if (CanCrouch() && input_buttons & INPUT_CROUCH) { + if (!IsCrouching()) { + testMins = g_pmoveVars.GetCrouchMins(); + testMaxs = g_pmoveVars.GetCrouchMaxs(); + + if (PMove_IsStuck(this, origin, testMins, testMaxs) == false) { + AddVFlags(VFL_CROUCHING); + stateChanged = true; + /*printf("Now crouch.\n");*/ + } + } + } else { + /* if we aren't ducking any longer, attempt to stand up */ + if (IsCrouching()) { + /*printf("No longer crouch.\n");*/ + + /* if they're going prone mode, we'll have to test that */ + if (input_buttons & INPUT_PRONE) { + testMins = g_pmoveVars.GetProneMins(); + testMaxs = g_pmoveVars.GetProneMaxs(); + /*printf("Want to prone.\n");*/ + } else { + testMins = g_pmoveVars.GetStandingMins(); + testMaxs = g_pmoveVars.GetStandingMaxs(); + /*printf("Want to stand.\n");*/ + } + + testOrigin[2] = (origin[2] + mins[2]) - testMins[2]; + + /* will we fit here? if not, don't remove the CROUCH flag */ + if (PMove_IsStuck(this, testOrigin, testMins, testMaxs) == false) { + RemoveVFlags(VFL_CROUCHING); + stateChanged = true; + /*printf("Fill fit.\n");*/ + } else if (PMove_IsStuck(this, testOrigin + [0,0,18], testMins, testMaxs) == false) { + RemoveVFlags(VFL_CROUCHING); + stateChanged = true; + crouchFix = true; + /*printf("Fill have to nudge up to 18 units.\n");*/ + } + } + } + /* state didn't change, don't update size */ + if (!stateChanged) + return; + + if (IsCrouching()) { + mins = g_pmoveVars.GetCrouchMins(); + maxs = g_pmoveVars.GetCrouchMaxs(); + /*printf("State change finished.\n");*/ + } else { + mins = testMins; + maxs = testMaxs; + + if (crouchFix == true && PMove_IsStuck(this, testOrigin, testMins, testMaxs)) { + /* check if we can get unstuck by testing up to a few units up */ + for (int i = 0; i < 18; i++) { + if (PMove_IsStuck(this, testOrigin, testMins, testMaxs) == false) { + /*printf("State change finished after %i units.\n", i);*/ + break; + } + testOrigin[2] += 1; + } + } + SetOrigin(testOrigin); + } +} + +void +NSClientPlayer::Physics_Prone(void) +{ + bool proneFix = false; + vector testOrigin = origin; + vector testMins = g_vec_null; + vector testMaxs = g_vec_null; + bool stateChanged = false; + + if (GetMovetype() != MOVETYPE_WALK) + return; + + if (CanProne() && input_buttons & INPUT_PRONE) { + if (!IsProne()) { + testMins = g_pmoveVars.GetProneMins(); + testMaxs = g_pmoveVars.GetProneMaxs(); + + if (PMove_IsStuck(this, origin, testMins, testMaxs) == false) { + AddVFlags(VFL_PRONE); + stateChanged = true; + /*printf("Now prone.\n");*/ + } + } } else { /* if we aren't holding down duck anymore and 'attempt' to stand up, prevent it */ - if (GetFlags() & FL_CROUCHING) { - vector vecTest = [0, 0, PHY_HULL_MAX[2]]; - if (PMove_IsStuck(this, vecTest, PHY_HULL_MIN, PHY_HULL_MAX) == FALSE) { - RemoveFlags(FL_CROUCHING); - crouchfix = true; + if (IsProne()) { + /*printf("No longer prone.\n");*/ + + /* if they're going prone mode, we'll have to test that */ + if (input_buttons & INPUT_CROUCH) { + testMins = g_pmoveVars.GetCrouchMins(); + testMaxs = g_pmoveVars.GetCrouchMaxs(); + /*printf("Want to crouch.\n");*/ + } else { + testMins = g_pmoveVars.GetStandingMins(); + testMaxs = g_pmoveVars.GetStandingMaxs(); + /*printf("Want to stand.\n");*/ + } + + testOrigin[2] = (origin[2] + mins[2]) - testMins[2]; + + /* will we fit? */ + if (PMove_IsStuck(this, testOrigin, testMins, testMaxs) == false) { + RemoveVFlags(VFL_PRONE); + stateChanged = true; + /*printf("Will fit.\n");*/ + } else if (PMove_IsStuck(this, testOrigin + [0, 0, 18], testMins, testMaxs) == false) { + RemoveVFlags(VFL_PRONE); + proneFix = true; + stateChanged = true; + /*printf("Fill have to nudge up to 18 units.\n");*/ } - } else { - RemoveFlags(FL_CROUCHING); } } - if (GetFlags() & FL_CROUCHING) { - SetSize(PHY_HULL_CROUCHED_MIN, PHY_HULL_CROUCHED_MAX); - view_ofs = PHY_VIEWPOS_CROUCHED; - } else { - SetSize(PHY_HULL_MIN, PHY_HULL_MAX); + /* prevent expensive operations. */ + if (!stateChanged) + return; - if (crouchfix == true && PMove_IsStuck(this, [0,0,0], PHY_HULL_MIN, PHY_HULL_MAX)) { + if (IsProne()) { + mins = g_pmoveVars.GetProneMins(); + maxs = g_pmoveVars.GetProneMaxs(); + /*printf("State change finished.\n");*/ + } else { + mins = testMins; + maxs = testMaxs; + origin = testOrigin; + + if (proneFix == true && PMove_IsStuck(this, origin, mins, maxs)) { /* check if we can get unstuck by testing up to a few units up */ - for (int i = 0; i < 36; i++) { - origin[2] += 1; - if (PMove_IsStuck(this, [0,0,0], mins, maxs) == FALSE) { + for (int i = 1; i < 18; i++) { + if (PMove_IsStuck(this, origin, mins, maxs) == false) { + /*printf("State change finished after %i units.\n", i);*/ break; } + origin[2] += 1; } } SetOrigin(origin); - view_ofs = PHY_VIEWPOS; } } @@ -150,7 +261,7 @@ NSClientPlayer::Physics_Jump(void) } else { /* standard jump here */ if (GetFlags() & FL_ONGROUND) - velocity[2] += PHY_JUMP_HEIGHT; + velocity[2] += g_pmoveVars.pm_jumpheight; } } @@ -159,7 +270,7 @@ void NSClientPlayer::Physics_CheckJump(float premove) { /* unset jump-key whenever it's not set */ - if (!(input_buttons & INPUT_BUTTON2)) { + if (!(input_buttons & INPUT_JUMP)) { AddFlags(FL_JUMPRELEASED); return; } @@ -171,10 +282,10 @@ NSClientPlayer::Physics_CheckJump(float premove) /* if a player wants to be able to hold jump, let them */ if (!(infokey(this, "autojump") == "1")) - if (!(GetFlags() & FL_JUMPRELEASED)) - return; + if (HasFlags(FL_JUMPRELEASED) == false) + return; - if (input_buttons & INPUT_BUTTON2 && premove) { + if (input_buttons & INPUT_JUMP && premove) { if (velocity[2] < 0) { velocity[2] = 0; } @@ -189,17 +300,14 @@ NSClientPlayer::Physics_CheckJump(float premove) void NSClientPlayer::Physics_SetViewParms(void) { - if (GetFlags() & FL_CROUCHING) { - mins = PHY_HULL_CROUCHED_MIN; - maxs = PHY_HULL_CROUCHED_MAX; - view_ofs = PHY_VIEWPOS_CROUCHED; + /* cheap operations */ + if (IsCrouching()) { + view_ofs = g_pmoveVars.GetCrouchViewOffset(); + } else if (IsProne()) { + view_ofs = g_pmoveVars.GetProneViewOffset(); } else { - mins = PHY_HULL_MIN; - maxs = PHY_HULL_MAX; - view_ofs = PHY_VIEWPOS; + view_ofs = g_pmoveVars.GetStandingViewOffset(); } - - SetSize(mins, maxs); } void @@ -223,7 +331,7 @@ NSClientPlayer::Physics_WaterJump(void) /* there's nothing preventing us from putting our hands up here */ if (trace_fraction == 1.0) { - velocity[2] = PHY_WATERJUMP_HEIGHT; + velocity[2] = g_pmoveVars.pm_waterjumpheight; AddFlags(FL_WATERJUMP); RemoveFlags(FL_JUMPRELEASED); return; @@ -304,9 +412,34 @@ NSClientPlayer::Physics_WaterMove(void) float NSClientPlayer::Physics_MaxSpeed(void) { - float maxValue = serverkeyfloat("phy_maxspeed"); - float wishSpeed = (GetFlags() & FL_CROUCHING) ? PMOVE_STEP_WALKSPEED : maxValue; - return min(wishSpeed, maxValue); + float wishSpeed = 0.0f; + float runSpeed = g_pmoveVars.pm_runspeed; + float maxStamina = g_pmoveVars.pm_stamina; + float crouchSpeed = g_pmoveVars.pm_crouchspeed; + float walkSpeed = g_pmoveVars.pm_walkspeed; + float proneSpeed = g_pmoveVars.pm_pronespeed; + + if (CanSprint() && IsSprinting()) { + if (m_flStamina < maxStamina) { + float slowDownThresh = g_pmoveVars.pm_staminathreshold; + + if ((m_flStamina + slowDownThresh) > maxStamina) { + float delta = (m_flStamina + slowDownThresh) - maxStamina; + /* change maxValue to something between 1.0 and 1.5 */ + runSpeed = lerp(runSpeed, walkSpeed, delta/slowDownThresh); + } + } + + wishSpeed = runSpeed; + } else if (IsCrouching()) { + wishSpeed = crouchSpeed; + } else if (IsProne()) { + wishSpeed = proneSpeed; + } else { + wishSpeed = walkSpeed; + } + + return wishSpeed; } void @@ -314,11 +447,7 @@ NSClientPlayer::Physics_InputPreMove(void) { NSVehicle currentVehicle = (NSVehicle)vehicle; bool canMove = true; - - /* when pressing the 'use' button, we also walk slower for precision */ - if (input_buttons & INPUT_BUTTON5) { - input_movevalues *= 0.25; - } + bool canFire = true; /* find all the valid ways to freeze a player... */ if (currentVehicle) { @@ -326,14 +455,25 @@ NSClientPlayer::Physics_InputPreMove(void) canMove = false; } - if (flags & FL_FROZEN || movetype == MOVETYPE_NONE) { + if (vv_flags & VFL_FROZEN || movetype == MOVETYPE_NONE) { canMove = false; } /* freeze in place */ if (canMove == false) { input_movevalues = [0,0,0]; - input_buttons &= ~INPUT_BUTTON2; + input_buttons &= ~INPUT_JUMP; + } + + /* freeze in place */ + if (vv_flags & VFL_NOATTACK) { + input_buttons &= ~INPUT_PRIMARY; + input_buttons &= ~INPUT_RELOAD; + } + + /* when pressing the 'use' button, we also walk slower for precision */ + if (input_buttons & INPUT_USE) { + input_movevalues *= 0.5; } /* clamp movement values to max speed */ @@ -349,8 +489,10 @@ NSClientPlayer::Physics_InputPreMove(void) /* suppress crouching in vehicles */ if (currentVehicle) { - if (currentVehicle.CanDriverCrouch() == false) - input_buttons &= ~INPUT_BUTTON8; + if (currentVehicle.CanDriverCrouch() == false) { + input_buttons &= ~INPUT_CROUCH; + input_buttons &= ~INPUT_PRONE; + } } } @@ -363,6 +505,21 @@ NSClientPlayer::Physics_InputPostMove(void) w_attack_next = max(0, w_attack_next - input_timelength); w_idle_next = max(0, w_idle_next - input_timelength); weapontime += input_timelength; + + if (input_buttons & INPUT_SPRINT) { + m_flStamina += input_timelength; + } else { + float toSubtract = input_timelength; + toSubtract *= g_pmoveVars.pm_staminarate; + m_flStamina = max(0, m_flStamina - toSubtract); + } + + if (m_flStamina > g_pmoveVars.pm_stamina) { + m_flStamina = g_pmoveVars.pm_stamina; + } + + //printf("stamina: %f\n", m_flStamina); + punch = max(0, 1.0f - (input_timelength * 4)); punchangle[0] *= punch; punchangle[1] *= punch; @@ -370,8 +527,6 @@ NSClientPlayer::Physics_InputPostMove(void) /* player animation code */ UpdatePlayerAnimation(input_timelength); - - RemoveFlags(FL_FROZEN); ProcessInput(); } @@ -382,10 +537,19 @@ NSClientPlayer::Physics_Run(void) float flFallVel = (flags & FL_ONGROUND) ? 0 : -velocity[2]; float flBaseVel = basevelocity[2]; bool wasOnGround = (flags & FL_ONGROUND) ? true : false; + bool sprintFail = false; saved_input_movevalues = input_movevalues; saved_input_buttons = input_buttons; + sprintFail = ((input_buttons & INPUT_CROUCH) || (input_buttons & INPUT_PRONE)) ? true : false; + + if (input_buttons & INPUT_SPRINT && sprintFail == false) { + AddVFlags(VFL_SPRINTING); + } else { + RemoveVFlags(VFL_SPRINTING); + } + /* maxspeed changes when crouching, TODO: make this game-specific */ maxspeed = Physics_MaxSpeed(); @@ -407,6 +571,7 @@ NSClientPlayer::Physics_Run(void) Physics_SetViewParms(); Physics_Crouch(); + Physics_Prone(); Physics_CheckJump(TRUE); #ifdef CUSTOMPLAYERPHYSICS @@ -429,10 +594,7 @@ NSClientPlayer::Physics_Run(void) input_movevalues = saved_input_movevalues; input_buttons = saved_input_buttons; Physics_InputPostMove(); - - angles[0] = Math_FixDelta(angles[0]); - angles[1] = Math_FixDelta(angles[1]); - angles[2] = Math_FixDelta(angles[2]); + angles = fixAngle(angles); #ifdef SERVER /* Use Flagger */ @@ -441,12 +603,13 @@ NSClientPlayer::Physics_Run(void) src = origin + view_ofs; dest = src + v_forward * 64; traceline(src, dest, MOVE_NORMAL, this); + RemoveVFlags(VFL_ONUSABLE); - RemoveFlags(FL_ONUSABLE); if (trace_ent.identity == 1) { NSEntity foo = (NSEntity)trace_ent; + if (foo.PlayerUse) { - flags |= FL_ONUSABLE; + AddVFlags(VFL_ONUSABLE); } } diff --git a/src/shared/pmove.h b/src/shared/pmove.h index 47ee98b6..4ddef413 100644 --- a/src/shared/pmove.h +++ b/src/shared/pmove.h @@ -30,8 +30,95 @@ typedef enum WATERLEVEL_SUBMERGED } waterlevel_t; + +/** This class networks pmove related variables to each client. */ +class +NSPMoveVars:NSEntity +{ +public: + void NSPMoveVars(void); + + NETWORKED_FLOAT(g_gravity) + NETWORKED_FLOAT(pm_accelerate) + NETWORKED_FLOAT(pm_airaccelerate) + NETWORKED_FLOAT(pm_airstepsize) + NETWORKED_FLOAT(pm_boxcenter) + NETWORKED_FLOAT(pm_boxwidth) + NETWORKED_FLOAT(pm_crouchheight) + NETWORKED_FLOAT(pm_crouchspeed) + NETWORKED_FLOAT(pm_crouchviewheight) + NETWORKED_FLOAT(pm_edgefriction) + NETWORKED_FLOAT(pm_friction) + NETWORKED_FLOAT(pm_gravity) + NETWORKED_FLOAT(pm_jumpheight) + NETWORKED_FLOAT(pm_maxviewpitch) + NETWORKED_FLOAT(pm_minviewpitch) + NETWORKED_FLOAT(pm_noclipaccelerate) + NETWORKED_FLOAT(pm_noclipspeed) + NETWORKED_FLOAT(pm_normalheight) + NETWORKED_FLOAT(pm_normalviewheight) + NETWORKED_FLOAT(pm_nospeedcap) + NETWORKED_FLOAT(pm_proneheight) + NETWORKED_FLOAT(pm_pronespeed) + NETWORKED_FLOAT(pm_proneviewheight) + NETWORKED_FLOAT(pm_runspeed) + NETWORKED_FLOAT(pm_stamina) + NETWORKED_FLOAT(pm_staminarate) + NETWORKED_FLOAT(pm_staminathreshold) + NETWORKED_FLOAT(pm_stepsize) + NETWORKED_FLOAT(pm_stopspeed) + NETWORKED_FLOAT(pm_walkspeed) + NETWORKED_FLOAT(pm_wateraccelerate) + NETWORKED_FLOAT(pm_waterjumpheight) + + /** Returns the standing player collision box mins. Calculated from pm_normalheight. */ + nonvirtual vector GetStandingMins(void); + /** Returns the standing player collision box maxs. */ + nonvirtual vector GetStandingMaxs(void); + /** Returns the standing player view offset. Calculated from pm_normalviewheight and pm_boxcenter. */ + nonvirtual vector GetStandingViewOffset(void); + /** Returns the crouching/ducked player collision box mins. */ + nonvirtual vector GetCrouchMins(void); + /** Returns the crouching/ducked player collision box maxs. */ + nonvirtual vector GetCrouchMaxs(void); + /** Returns the crouching/ducked player view offset. Calculated from pm_crouchviewheight and pm_boxcenter. */ + nonvirtual vector GetCrouchViewOffset(void); + /** Returns the prone player collision box maxs. */ + nonvirtual vector GetProneMins(void); + /** Returns the prone player collision box maxs. */ + nonvirtual vector GetProneMaxs(void); + /** Returns the prone player view offset. Calculated from pm_proneviewheight and pm_boxcenter. */ + nonvirtual vector GetProneViewOffset(void); + #ifdef SERVER -void PMove_StartFrame(void); + virtual void Respawn(void); + virtual void EvaluateEntity(void); + virtual bool SendEntity(entity, float); #endif -void PMove_Init(void); \ No newline at end of file +#ifdef CLIENT + virtual void ReceiveEntity(float, float); +#endif + +private: + nonvirtual void UpdateBoundingBoxes(void); + + vector m_vecStandingMins; + vector m_vecStandingMaxs; + vector m_vecCrouchMins; + vector m_vecCrouchMaxs; + vector m_vecProneMins; + vector m_vecProneMaxs; + vector m_vecNormalViewOffset; + vector m_vecCrouchViewOffset; + vector m_vecProneViewOffset; +}; + +/** The global, shared object containing all currently valid pmove parameters. */ +NSPMoveVars g_pmoveVars; + +/** Called by Nuclide. Sets up g_pmoveVars. */ +void PMove_Init(void); + +void PMoveCustom_RunPlayerPhysics(entity); +void PMoveCustom_RunCrouchPhysics(entity); \ No newline at end of file diff --git a/src/shared/pmove.qc b/src/shared/pmove.qc index cf8a0f3f..9bffef28 100644 --- a/src/shared/pmove.qc +++ b/src/shared/pmove.qc @@ -18,138 +18,440 @@ #ifdef CUSTOMPLAYERPHYSICS void PMoveCustom_Init(void); - #ifdef SERVER - void PMoveCustom_StartFrame(void); - #endif #endif #ifndef PMOVE_STEPHEIGHT #define PMOVE_STEPHEIGHT 18 #endif +var int autocvar_pm_stepsize = PMOVE_STEPHEIGHT; #ifndef PMOVE_AIRSTEPHEIGHT #define PMOVE_AIRSTEPHEIGHT 18 #endif +var int autocvar_pm_airstepsize = PMOVE_AIRSTEPHEIGHT; #ifndef PMOVE_FRICTION #define PMOVE_FRICTION 4 #endif +var float autocvar_pm_friction = PMOVE_FRICTION; #ifndef PMOVE_EDGEFRICTION #define PMOVE_EDGEFRICTION 1 #endif +var float autocvar_pm_edgefriction = PMOVE_EDGEFRICTION; #ifndef PMOVE_STOPSPEED #define PMOVE_STOPSPEED 75 #endif +var float autocvar_pm_stopspeed = PMOVE_STOPSPEED; #ifndef PMOVE_GRAVITY #define PMOVE_GRAVITY 800 #endif +var float autocvar_pm_gravity = PMOVE_GRAVITY; #ifndef PMOVE_AIRACCELERATE #define PMOVE_AIRACCELERATE 10 #endif +var float autocvar_pm_airaccelerate = PMOVE_AIRACCELERATE; #ifndef PMOVE_WATERACCELERATE #define PMOVE_WATERACCELERATE 8 #endif +var float autocvar_pm_wateraccelerate = PMOVE_WATERACCELERATE; #ifndef PMOVE_ACCELERATE #define PMOVE_ACCELERATE 8 #endif - -#ifndef PMOVE_MAXSPEED - #define PMOVE_MAXSPEED 270 -#endif +var float autocvar_pm_accelerate = PMOVE_ACCELERATE; #ifndef PMOVE_STEP_WALKSPEED - #define PMOVE_STEP_WALKSPEED 135 + #define PMOVE_STEP_WALKSPEED 190 #endif +var float autocvar_pm_walkspeed = PMOVE_STEP_WALKSPEED; #ifndef PMOVE_STEP_RUNSPEED - #define PMOVE_STEP_RUNSPEED 220 + #define PMOVE_STEP_RUNSPEED (PMOVE_STEP_WALKSPEED * 1.5) #endif +var float autocvar_pm_runspeed = PMOVE_STEP_RUNSPEED; -#ifndef PHY_VIEWPOS - #define PHY_VIEWPOS [0,0,28] +#ifndef PMOVE_STEP_CROUCHSPEED + #define PMOVE_STEP_CROUCHSPEED (PMOVE_STEP_WALKSPEED * 0.65f) #endif +var float autocvar_pm_crouchspeed = PMOVE_STEP_CROUCHSPEED; -#ifndef PHY_VIEWPOS_CROUCHED - #define PHY_VIEWPOS_CROUCHED [0,0,12] +#ifndef PMOVE_STEP_PRONESPEED + #define PMOVE_STEP_PRONESPEED (PMOVE_STEP_WALKSPEED * 0.15) #endif +var float autocvar_pm_pronespeed = PMOVE_STEP_PRONESPEED; /* stamina system, inspired by idTech 4 */ #ifndef PMOVE_STAMINA #define PMOVE_STAMINA 24 #endif +var float autocvar_pm_stamina = PMOVE_STAMINA; #ifndef PMOVE_STAMINARATE #define PMOVE_STAMINARATE 0.75 #endif +var float autocvar_pm_staminarate = PMOVE_STAMINARATE; #ifndef PMOVE_STAMINATHRESHOLD #define PMOVE_STAMINATHRESHOLD 4 #endif +var float autocvar_pm_staminathreshold = PMOVE_STAMINATHRESHOLD; #ifndef PMOVE_NOCLIPSPEED #define PMOVE_NOCLIPSPEED 500 #endif +var float autocvar_pm_noclipspeed = PMOVE_NOCLIPSPEED; #ifndef PMOVE_NOCLIPACCELERATE #define PMOVE_NOCLIPACCELERATE 5 #endif +var float autocvar_pm_noclipaccelerate = PMOVE_NOCLIPACCELERATE; - -/* Those are constant for HL BSP and CANNOT be changed. - * Blame Valve for purchasing a Quake II license but not - * scrapping hull sizes for their .bsp format... - * however, you can offset them */ -#ifndef PHY_HULL_MIN - #define PHY_HULL_MIN [-16,-16,-36] +#ifndef PMOVE_JUMP_HEIGHT + #define PMOVE_JUMP_HEIGHT 240 #endif +var float autocvar_pm_jumpheight = PMOVE_JUMP_HEIGHT; -#ifndef PHY_HULL_MAX - #define PHY_HULL_MAX [16,16,36] +#ifndef PMOVE_WATERJUMP_HEIGHT + #define PMOVE_WATERJUMP_HEIGHT 350 #endif +var float autocvar_pm_waterjumpheight = PMOVE_WATERJUMP_HEIGHT; -#ifndef PHY_HULL_CROUCHED_MIN - #define PHY_HULL_CROUCHED_MIN [-16,-16,-18] +#ifndef PMOVE_BOXCENTER + #define PMOVE_BOXCENTER true #endif +var bool autocvar_pm_boxcenter = PMOVE_BOXCENTER; -#ifndef PHY_HULL_CROUCHED_MAX - #define PHY_HULL_CROUCHED_MAX [16,16,18] +#ifndef PMOVE_BOXWIDTH + #define PMOVE_BOXWIDTH 32 #endif +var float autocvar_pm_boxwidth = PMOVE_BOXWIDTH; + +var float autocvar_pm_maxviewpitch = 89; +var float autocvar_pm_minviewpitch = -89; + + +#ifndef PMOVE_NORMAL_HEIGHT + #define PMOVE_NORMAL_HEIGHT 74 +#endif +var float autocvar_pm_normalheight = PMOVE_NORMAL_HEIGHT; + +#ifndef PMOVE_NORMAL_VIEWHEIGHT + #define PMOVE_NORMAL_VIEWHEIGHT 68 +#endif +var float autocvar_pm_normalviewheight = PMOVE_NORMAL_VIEWHEIGHT; + +#ifndef PMOVE_CROUCH_HEIGHT + #define PMOVE_CROUCH_HEIGHT 38 +#endif +var float autocvar_pm_crouchheight = PMOVE_CROUCH_HEIGHT; + +#ifndef PMOVE_CROUCH_VIEWHEIGHT + #define PMOVE_CROUCH_VIEWHEIGHT 32 +#endif +var float autocvar_pm_crouchviewheight = PMOVE_CROUCH_VIEWHEIGHT; + +#ifndef PMOVE_PRONE_HEIGHT + #define PMOVE_PRONE_HEIGHT 20 +#endif +var float autocvar_pm_proneheight = PMOVE_PRONE_HEIGHT; + +#ifndef PMOVE_PRONE_VIEWHEIGHT + #define PMOVE_PRONE_VIEWHEIGHT 16 +#endif +var float autocvar_pm_proneviewheight = PMOVE_PRONE_VIEWHEIGHT; /* if they're undefined by a config, they'll be set by the game/mod default */ -var float autocvar_pm_stepsize = PMOVE_STEPHEIGHT; -var float autocvar_pm_airstepsize = PMOVE_AIRSTEPHEIGHT; -var float autocvar_pm_friction = PMOVE_FRICTION; -var float autocvar_pm_edgefriction = PMOVE_EDGEFRICTION; -var float autocvar_pm_stopspeed = PMOVE_STOPSPEED; -var float autocvar_pm_airaccelerate = PMOVE_AIRACCELERATE; -var float autocvar_pm_wateraccelerate = PMOVE_WATERACCELERATE; -var float autocvar_pm_accelerate = PMOVE_ACCELERATE; -var float autocvar_pm_maxspeed = PMOVE_MAXSPEED; var float autocvar_g_gravity = PMOVE_GRAVITY; var bool autocvar_pm_nospeedcap = false; +/* these are not tied to cvars, because clients (cl) and bots (bot) select +separate cvars for overriding their speeds. */ +#ifndef PMOVE_FORWARD_SPEED + #define PMOVE_FORWARD_SPEED 190.0f +#endif + +#ifndef PMOVE_SIDE_SPEED + #define PMOVE_SIDE_SPEED 152.0f +#endif + +#ifndef PMOVE_BACK_SPEED + #define PMOVE_BACK_SPEED 133.0f +#endif + +/* TODO: optimise. */ +#define PMOVEVARS_UPDATE 1 + +void +NSPMoveVars::NSPMoveVars(void) +{ + +} + +void +NSPMoveVars::UpdateBoundingBoxes(void) +{ + float halfWidth = pm_boxwidth * 0.5f; + float halfHeight = pm_normalheight * 0.5f; + m_vecStandingMins = [-halfWidth, -halfWidth, 0]; + m_vecStandingMaxs = [halfWidth, halfWidth, pm_normalheight]; + m_vecCrouchMins = [-halfWidth, -halfWidth, 0]; + m_vecCrouchMaxs = [halfWidth, halfWidth, pm_crouchheight]; + m_vecProneMins = [-halfHeight, -halfHeight, 0]; + m_vecProneMaxs = [halfHeight, halfHeight, pm_proneheight]; + + m_vecNormalViewOffset = + m_vecCrouchViewOffset = + m_vecProneViewOffset = g_vec_null; + + m_vecNormalViewOffset[2] = pm_normalviewheight; + m_vecCrouchViewOffset[2] = pm_crouchviewheight; + m_vecProneViewOffset[2] = pm_proneviewheight; + + if (pm_boxcenter == true) { + m_vecStandingMins[2] -= (pm_normalheight * 0.5f); + m_vecStandingMaxs[2] -= (pm_normalheight * 0.5f); + m_vecCrouchMins[2] -= (pm_crouchheight * 0.5f); + m_vecCrouchMaxs[2] -= (pm_crouchheight * 0.5f); + m_vecProneMins[2] -= (pm_proneheight * 0.5f); + m_vecProneMaxs[2] -= (pm_proneheight * 0.5f); + + m_vecNormalViewOffset[2] -= (pm_normalheight * 0.5f); + m_vecCrouchViewOffset[2] -= (pm_crouchheight * 0.5f); + m_vecProneViewOffset[2] -= (pm_proneheight * 0.5f); + } +} + +#ifdef SERVER +void +NSPMoveVars::Respawn(void) +{ + pvsflags = PVSF_IGNOREPVS; +} + +void +NSPMoveVars::EvaluateEntity(void) +{ + g_gravity = autocvar_g_gravity; + pm_accelerate = autocvar_pm_accelerate; + pm_airaccelerate = autocvar_pm_airaccelerate; + pm_airstepsize = autocvar_pm_airstepsize; + pm_boxcenter = autocvar_pm_boxcenter; + pm_boxwidth = autocvar_pm_boxwidth; + pm_crouchheight = autocvar_pm_crouchheight; + pm_crouchspeed = autocvar_pm_crouchspeed; + pm_crouchviewheight = autocvar_pm_crouchviewheight; + pm_edgefriction = autocvar_pm_edgefriction; + pm_friction = autocvar_pm_friction; + pm_gravity = autocvar_pm_gravity; + pm_jumpheight = autocvar_pm_jumpheight; + pm_maxviewpitch = autocvar_pm_maxviewpitch; + pm_minviewpitch = autocvar_pm_minviewpitch; + pm_noclipaccelerate = autocvar_pm_noclipaccelerate; + pm_noclipspeed = autocvar_pm_noclipspeed; + pm_normalheight = autocvar_pm_normalheight; + pm_normalviewheight = autocvar_pm_normalviewheight; + pm_nospeedcap = autocvar_pm_nospeedcap; + pm_proneheight = autocvar_pm_proneheight; + pm_pronespeed = autocvar_pm_pronespeed; + pm_proneviewheight = autocvar_pm_proneviewheight; + pm_runspeed = autocvar_pm_runspeed; + pm_stamina = autocvar_pm_stamina; + pm_staminarate = autocvar_pm_staminarate; + pm_staminathreshold = autocvar_pm_staminathreshold; + pm_stepsize = autocvar_pm_stepsize; + pm_stopspeed = autocvar_pm_stopspeed; + pm_walkspeed = autocvar_pm_walkspeed; + pm_wateraccelerate = autocvar_pm_wateraccelerate; + pm_waterjumpheight = autocvar_pm_waterjumpheight; + + EVALUATE_FIELD(g_gravity, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_accelerate, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_airaccelerate, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_airstepsize, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_boxcenter, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_boxwidth, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_crouchheight, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_crouchspeed, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_crouchviewheight, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_edgefriction, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_friction, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_gravity, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_jumpheight, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_maxviewpitch, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_minviewpitch, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_noclipaccelerate, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_noclipspeed, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_normalheight, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_normalviewheight, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_nospeedcap, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_proneheight, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_pronespeed, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_proneviewheight, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_runspeed, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_stamina, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_staminarate, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_staminathreshold, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_stepsize, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_stopspeed, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_walkspeed, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_wateraccelerate, PMOVEVARS_UPDATE) + EVALUATE_FIELD(pm_waterjumpheight, PMOVEVARS_UPDATE) + UpdateBoundingBoxes(); +} + +bool +NSPMoveVars::SendEntity(entity pvsEnt, float flChanged) +{ + WriteByte(MSG_ENTITY, ENT_PMOVEVARS); + WriteFloat(MSG_ENTITY, flChanged); + + SENDENTITY_FLOAT(g_gravity, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_accelerate, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_airaccelerate, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_airstepsize, PMOVEVARS_UPDATE) + SENDENTITY_BYTE(pm_boxcenter, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_boxwidth, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_crouchheight, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_crouchspeed, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_crouchviewheight, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_edgefriction, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_friction, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_gravity, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_jumpheight, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_maxviewpitch, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_minviewpitch, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_noclipaccelerate, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_noclipspeed, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_normalheight, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_normalviewheight, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_nospeedcap, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_proneheight, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_pronespeed, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_proneviewheight, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_runspeed, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_stamina, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_staminarate, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_staminathreshold, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_stepsize, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_stopspeed, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_walkspeed, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_wateraccelerate, PMOVEVARS_UPDATE) + SENDENTITY_FLOAT(pm_waterjumpheight, PMOVEVARS_UPDATE) + return (true); +} +#endif + +#ifdef CLIENT +void +NSPMoveVars::ReceiveEntity(float flNew, float flChanged) +{ + READENTITY_FLOAT(g_gravity, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_accelerate, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_airaccelerate, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_airstepsize, PMOVEVARS_UPDATE) + READENTITY_BYTE(pm_boxcenter, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_boxwidth, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_crouchheight, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_crouchspeed, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_crouchviewheight, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_edgefriction, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_friction, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_gravity, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_jumpheight, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_maxviewpitch, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_minviewpitch, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_noclipaccelerate, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_noclipspeed, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_normalheight, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_normalviewheight, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_nospeedcap, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_proneheight, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_pronespeed, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_proneviewheight, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_runspeed, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_stamina, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_staminarate, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_staminathreshold, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_stepsize, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_stopspeed, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_walkspeed, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_wateraccelerate, PMOVEVARS_UPDATE) + READENTITY_FLOAT(pm_waterjumpheight, PMOVEVARS_UPDATE) + + if (flNew) { + g_pmoveVars = this; + } + + UpdateBoundingBoxes(); +} +#endif + +vector +NSPMoveVars::GetStandingMins(void) +{ + return (m_vecStandingMins); +} + +vector +NSPMoveVars::GetStandingMaxs(void) +{ + return (m_vecStandingMaxs); +} + +vector +NSPMoveVars::GetCrouchMins(void) +{ + return (m_vecCrouchMins); +} + +vector +NSPMoveVars::GetCrouchMaxs(void) +{ + return (m_vecCrouchMaxs); +} + +vector +NSPMoveVars::GetProneMins(void) +{ + return (m_vecProneMins); +} + +vector +NSPMoveVars::GetProneMaxs(void) +{ + return (m_vecProneMaxs); +} + +vector +NSPMoveVars::GetStandingViewOffset(void) +{ + return (m_vecNormalViewOffset); +} + +vector +NSPMoveVars::GetCrouchViewOffset(void) +{ + return (m_vecCrouchViewOffset); +} + +vector +NSPMoveVars::GetProneViewOffset(void) +{ + return (m_vecProneViewOffset); +} + void PMove_Init(void) { #ifdef SERVER - cvar_set("pm_stepsize", ftos(PMOVE_STEPHEIGHT)); - cvar_set("pm_airstepsize", ftos(PMOVE_AIRSTEPHEIGHT)); - cvar_set("pm_friction", ftos(PMOVE_FRICTION)); - cvar_set("pm_edgefriction", ftos(PMOVE_EDGEFRICTION)); - cvar_set("pm_stopspeed", ftos(PMOVE_STOPSPEED)); - cvar_set("pm_airaccelerate", ftos(PMOVE_AIRACCELERATE)); - cvar_set("pm_wateraccelerate", ftos(PMOVE_WATERACCELERATE)); - cvar_set("pm_accelerate", ftos(PMOVE_ACCELERATE)); - cvar_set("pm_maxspeed", ftos(PMOVE_MAXSPEED)); - cvar_set("pm_noclipspeed", ftos(PMOVE_NOCLIPSPEED)); - cvar_set("pm_noclipaccelerate", ftos(PMOVE_NOCLIPACCELERATE)); - cvar_set("g_gravity", ftos(PMOVE_GRAVITY)); /* global */ + if (!g_pmoveVars) { + g_pmoveVars = spawn(NSPMoveVars); + } #endif #ifdef CUSTOMPLAYERPHYSICS @@ -157,27 +459,14 @@ PMove_Init(void) #endif } -#ifdef SERVER -void -PMove_StartFrame(void) -{ - #ifdef CUSTOMPLAYERPHYSICS - PMoveCustom_StartFrame(); - #endif -} -#endif - /* simple bounds check */ bool -PMove_IsStuck(entity eTarget, vector vOffset, vector vecMins, vector vecMaxs) +PMove_IsStuck(entity eTarget, vector testOrg, vector vecMins, vector vecMaxs) { - vector bound; - if (eTarget.solid != SOLID_SLIDEBOX) { return (0); } - bound = eTarget.origin + vOffset; - tracebox(bound, vecMins, vecMaxs, bound, MOVE_NORMAL, eTarget); + tracebox(testOrg, vecMins, vecMaxs, testOrg, MOVE_NORMAL, eTarget); return trace_startsolid; } diff --git a/src/shared/pmove_custom.qc b/src/shared/pmove_custom.qc index b654ef69..41d2bca8 100644 --- a/src/shared/pmove_custom.qc +++ b/src/shared/pmove_custom.qc @@ -21,36 +21,6 @@ PMoveCustom_Init(void) } -#ifdef SERVER -/* we need to network our changes everytime cvars are updated */ -void -PMoveCustom_UpdateVar(string info, string cv) -{ - float d = cvar(cv); - if (serverkeyfloat(info) != d) { - readcmd(sprintf("serverinfo %s %d\n", info, d)); - } -} - -void -PMoveCustom_StartFrame(void) -{ - PMoveCustom_UpdateVar("phy_stepheight", "pm_stepsize"); - PMoveCustom_UpdateVar("phy_airstepheight", "pm_airstepsize"); - PMoveCustom_UpdateVar("phy_friction", "pm_friction"); - PMoveCustom_UpdateVar("phy_edgefriction", "pm_edgefriction"); - PMoveCustom_UpdateVar("phy_stopspeed", "pm_stopspeed"); - PMoveCustom_UpdateVar("phy_gravity", "g_gravity"); - PMoveCustom_UpdateVar("phy_airaccelerate", "pm_airaccelerate"); - PMoveCustom_UpdateVar("phy_wateraccelerate", "pm_wateraccelerate"); - PMoveCustom_UpdateVar("phy_accelerate", "pm_accelerate"); - PMoveCustom_UpdateVar("phy_maxspeed", "pm_maxspeed"); - PMoveCustom_UpdateVar("phy_noclipspeed", "pm_noclipspeed"); - PMoveCustom_UpdateVar("phy_noclipaccelerate", "pm_noclipaccelerate"); - PMoveCustom_UpdateVar("phy_nospeedcap", "pm_nospeedcap"); -} -#endif - /* pointcontents reimplementation, only way we can effectively trace * against ladders and liquids that are defined in the game-logic. */ @@ -69,9 +39,9 @@ float PMoveCustom_Gravity(entity ent) { if (ent.gravity) { - return serverkeyfloat("phy_gravity") * ent.gravity; + return g_pmoveVars.g_gravity * ent.gravity; } else { - return serverkeyfloat("phy_gravity"); + return g_pmoveVars.g_gravity; } } @@ -137,9 +107,9 @@ PMoveCustom_Categorize(void) #else if (trace_endcontentsi & CONTENTBIT_FTELADDER) { #endif - self.flags |= FL_ONLADDER; + self.vv_flags |= VFL_ONLADDER; } else { - self.flags &= ~FL_ONLADDER; + self.vv_flags &= ~VFL_ONLADDER; } testPos = self.origin + [0, 0, self.mins[2] + 4]; @@ -156,7 +126,7 @@ PMoveCustom_Categorize(void) } /* how far underwater are we? */ - if (contents < CONTENT_SOLID && !(self.flags & FL_ONLADDER)) { + if (contents < CONTENT_SOLID && !(self.vv_flags & VFL_ONLADDER)) { self.watertype = contents; if (PMoveCustom_Contents(self.origin + (self.mins + self.maxs) * 0.5) @@ -203,7 +173,7 @@ PMoveCustom_AccelWater(float move_time, float premove) wish_speed = vlen(vecWishVel); - if (serverkeyfloat("phy_nospeedcap") == 0 && wish_speed > self.maxspeed) { + if (g_pmoveVars.pm_nospeedcap == 0 && wish_speed > self.maxspeed) { wish_speed = self.maxspeed; } @@ -211,7 +181,7 @@ PMoveCustom_AccelWater(float move_time, float premove) // water friction if (self.velocity != [0,0,0]) { - flFriction = vlen(self.velocity) * (1 - move_time * serverkeyfloat("phy_friction")); + flFriction = vlen(self.velocity) * (1 - move_time * g_pmoveVars.pm_friction); if (flFriction > 0) { self.velocity = normalize(self.velocity) * flFriction; } else { @@ -226,7 +196,7 @@ PMoveCustom_AccelWater(float move_time, float premove) return; } - flFriction = min(wish_speed - flFriction, serverkeyfloat("phy_wateraccelerate") * wish_speed * move_time); + flFriction = min(wish_speed - flFriction, g_pmoveVars.pm_wateraccelerate * wish_speed * move_time); self.velocity = self.velocity + normalize(vecWishVel) * flFriction; } @@ -245,7 +215,7 @@ PMoveCustom_AccelLadder(float move_time, float premove, vector wish_dir, float w self.velocity = [0,0,0]; } - if (input_buttons & INPUT_BUTTON2) { + if (input_buttons & INPUT_JUMP) { vector ladderpos = trace_ent.absmin + (0.5f * (trace_ent.absmax - trace_ent.absmin)); ladderpos[2] = self.origin[2]; makevectors(normalize(ladderpos - self.origin)); @@ -275,7 +245,7 @@ PMoveCustom_AccelFriction(float move_time, float premove, vector wish_dir, float } #endif - flApplyFriction = serverkeyfloat("phy_friction"); + flApplyFriction = g_pmoveVars.pm_friction; /* per frame basis friction modifier */ if (self.friction != 0.0f) { @@ -299,14 +269,14 @@ PMoveCustom_AccelFriction(float move_time, float premove, vector wish_dir, float // apply friction if (trace_fraction == 1.0) { - if (flFriction < serverkeyfloat("phy_stopspeed")) { - flFriction = 1 - move_time * (serverkeyfloat("phy_stopspeed") / flFriction) * flApplyFriction * serverkeyfloat("phy_edgefriction"); + if (flFriction < g_pmoveVars.pm_stopspeed) { + flFriction = 1 - move_time * (g_pmoveVars.pm_stopspeed / flFriction) * flApplyFriction * g_pmoveVars.pm_edgefriction; } else { - flFriction = 1 - move_time * flApplyFriction * serverkeyfloat("phy_edgefriction"); + flFriction = 1 - move_time * flApplyFriction * g_pmoveVars.pm_edgefriction; } } else { - if (flFriction < serverkeyfloat("phy_stopspeed")) { - flFriction = 1 - move_time * (serverkeyfloat("phy_stopspeed") / flFriction) * flApplyFriction; + if (flFriction < g_pmoveVars.pm_stopspeed) { + flFriction = 1 - move_time * (g_pmoveVars.pm_stopspeed / flFriction) * flApplyFriction; } else { flFriction = 1 - move_time * flApplyFriction; @@ -328,7 +298,7 @@ PMoveCustom_AccelFriction(float move_time, float premove, vector wish_dir, float // acceleration flFriction = wish_speed - (self.velocity * wish_dir); if (flFriction > 0) { - self.velocity += wish_dir * min(flFriction, serverkeyfloat("phy_accelerate") * move_time * wish_speed); + self.velocity += wish_dir * min(flFriction, g_pmoveVars.pm_accelerate * move_time * wish_speed); } } @@ -339,7 +309,7 @@ PMoveCustom_AccelNoclip(float move_time, float premove, vector wish_dir, float w float flFriction; vector vecTemp; - flApplyFriction = serverkeyfloat("phy_friction"); + flApplyFriction = g_pmoveVars.pm_friction; /* per frame basis friction modifier */ if (self.friction != 0.0f) { @@ -348,12 +318,12 @@ PMoveCustom_AccelNoclip(float move_time, float premove, vector wish_dir, float w } /* apply friction */ - if (vlen(self.velocity)) { + if (lengthSquared(self.velocity)) { vecTemp = self.velocity; flFriction = vlen(vecTemp); - if (flFriction < serverkeyfloat("phy_stopspeed")) { - flFriction = 1 - move_time * (serverkeyfloat("phy_stopspeed") / flFriction) * flApplyFriction; + if (flFriction < g_pmoveVars.pm_stopspeed) { + flFriction = 1 - move_time * (g_pmoveVars.pm_stopspeed / flFriction) * flApplyFriction; } else { flFriction = 1 - move_time * flApplyFriction; } @@ -368,7 +338,7 @@ PMoveCustom_AccelNoclip(float move_time, float premove, vector wish_dir, float w // acceleration flFriction = wish_speed - (self.velocity * wish_dir); if (flFriction > 0) { - self.velocity += wish_dir * min(flFriction, serverkeyfloat("phy_noclipaccelerate") * move_time * wish_speed); + self.velocity += wish_dir * min(flFriction, g_pmoveVars.pm_noclipaccelerate * move_time * wish_speed); } } @@ -388,7 +358,7 @@ PMoveCustom_AccelGravity(float move_time, float premove, vector wish_dir, float if (flFriction > 0) { float fric; - fric = min(flFriction, serverkeyfloat("phy_airaccelerate") * wish_speed * move_time); + fric = min(flFriction, g_pmoveVars.pm_airaccelerate * wish_speed * move_time); self.velocity += wish_dir * fric; } } @@ -425,7 +395,7 @@ PMoveCustom_Acceleration(float move_time, float premove) vecWishVel += v_right * input_movevalues[1]; vecWishVel += v_up * input_movevalues[2]; wish_dir = normalize(vecWishVel); - wish_speed = serverkeyfloat("phy_noclipspeed"); + wish_speed = g_pmoveVars.pm_noclipspeed; PMoveCustom_AccelNoclip(move_time, premove, wish_dir, wish_speed); return; } @@ -449,11 +419,11 @@ PMoveCustom_Acceleration(float move_time, float premove) wish_dir = normalize(vecWishVel); wish_speed = vlen(vecWishVel); - if (serverkeyfloat("phy_nospeedcap") == 0 && wish_speed > self.maxspeed) { + if (g_pmoveVars.pm_nospeedcap == 0 && wish_speed > self.maxspeed) { wish_speed = self.maxspeed; } - if (self.flags & FL_ONLADDER) { + if (self.vv_flags & VFL_ONLADDER) { PMoveCustom_AccelLadder(move_time, premove, wish_dir, wish_speed); } else if (self.flags & FL_ONGROUND) { PMoveCustom_AccelFriction(move_time, premove, wish_dir, wish_speed); @@ -603,9 +573,9 @@ PMoveCustom_Move(void) trace_endpos = self.origin; if (self.flags & FL_ONGROUND) { - trace_endpos[2] += serverkeyfloat("phy_stepheight"); + trace_endpos[2] += g_pmoveVars.pm_stepsize; } else { - trace_endpos[2] += serverkeyfloat("phy_airstepheight"); + trace_endpos[2] += g_pmoveVars.pm_airstepsize; } tracebox(self.origin, self.mins, self.maxs, trace_endpos, MOVE_NORMAL, self); @@ -666,7 +636,7 @@ PMoveCustom_Move(void) /* touch whatever is below */ if (self.flags & FL_ONGROUND) { dest = self.origin; - dest[2] -= serverkeyfloat("phy_stepheight"); + dest[2] -= g_pmoveVars.pm_stepsize; tracebox(self.origin, self.mins, self.maxs, dest, MOVE_NORMAL, self); if (trace_fraction == 1.0) { @@ -712,11 +682,11 @@ PMoveCustom_RunPlayerPhysics(entity target) if (flying == true) { /* move camera up (noclip, fly) when holding jump */ - if (input_buttons & INPUT_BUTTON2) { + if (input_buttons & INPUT_JUMP) { input_movevalues[2] = 240; } /* move camera down (noclip, fly) when holding crouching */ - if (input_buttons & INPUT_BUTTON8) { + if (input_buttons & INPUT_CROUCH) { input_movevalues[2] = -240; } } @@ -753,22 +723,23 @@ PMoveCustom_RunCrouchPhysics(entity target) if (target.movetype == MOVETYPE_NONE) return; +#if 0 int iFixCrouch = FALSE; - if (input_buttons & INPUT_BUTTON8) { - target.flags |= FL_CROUCHING; + if (input_buttons & INPUT_CROUCH) { + target.vv_flags |= VFL_CROUCHING; } else { // If we aren't holding down duck anymore and 'attempt' to stand up, prevent it - if (target.flags & FL_CROUCHING) { - if (PMove_IsStuck(target, [0,0,36], PHY_HULL_MIN, PHY_HULL_MAX) == false) { - target.flags &= ~FL_CROUCHING; + if (target.vv_flags & VFL_CROUCHING) { + if (PMove_IsStuck(target, [0,0,36], g_pmoveVars.GetStandingMins(), g_pmoveVars.GetStandingMaxs()) == false) { + target.vv_flags &= ~VFL_CROUCHING; iFixCrouch = TRUE; } } else { - target.flags &= ~FL_CROUCHING; + target.vv_flags &= ~VFL_CROUCHING; } } - if (target.flags & FL_CROUCHING) { + if (target.vv_flags & VFL_CROUCHING) { setsize(target, PHY_HULL_CROUCHED_MIN, PHY_HULL_CROUCHED_MAX); target.view_ofs = PHY_VIEWPOS_CROUCHED; } else { @@ -784,5 +755,7 @@ PMoveCustom_RunCrouchPhysics(entity target) setorigin(target, target.origin); target.view_ofs = PHY_VIEWPOS; } +#endif + PMoveCustom_RunPlayerPhysics(target); } diff --git a/src/shared/sound.qc b/src/shared/sound.qc index 5c219b72..58ccaf2f 100644 --- a/src/shared/sound.qc +++ b/src/shared/sound.qc @@ -577,7 +577,7 @@ Sound_Play(entity target, int chan, string shader) float volume; float radius; float pitch; - int flag; + float flag; int sample; if (shader == "") @@ -622,12 +622,9 @@ Sound_Play(entity target, int chan, string shader) if (g_sounds[sample].flags & SNDFL_STEP) { float s = vlen(target.velocity); - /*if (target.flags & FL_CROUCHING) - s *= 2.0f;*/ - - if (s < PMOVE_STEP_WALKSPEED) { + if (s <= (g_pmoveVars.pm_walkspeed * 0.5)) { return; - } else if (s < PMOVE_STEP_RUNSPEED) { + } else if (s <= g_pmoveVars.pm_walkspeed) { volume *= 0.35f; } else { volume *= 0.75f; diff --git a/base/src/shared/weapon_common.h b/src/shared/weapon_common.h similarity index 52% rename from base/src/shared/weapon_common.h rename to src/shared/weapon_common.h index 1aac488d..60be10cb 100644 --- a/base/src/shared/weapon_common.h +++ b/src/shared/weapon_common.h @@ -38,46 +38,48 @@ typedef struct string() wmodel; string() deathmsg; - /* player specific */ - string(player) pmodel; - float(player) aimanim; - weapontype_t(player) type; /* required for bot-AI */ - void(player) draw; - void(player) holster; - void(player) primary; - void(player) secondary; - void(player) reload; - void(player) release; - int(player, int, int) pickup; - void(player) updateammo; + /* NSClientPlayer specific */ + string(NSClientPlayer) pmodel; + float(NSClientPlayer) aimanim; + weapontype_t(NSClientPlayer) type; /* required for bot-AI */ + void(NSClientPlayer) draw; + void(NSClientPlayer) holster; + void(NSClientPlayer) primary; + void(NSClientPlayer) secondary; + void(NSClientPlayer) reload; + void(NSClientPlayer) release; + int(NSClientPlayer, int, int) pickup; + void(NSClientPlayer) updateammo; - void(player, int) predraw; /* predraw... */ - void(player) postdraw; /* postdraw... */ + void(NSClientPlayer, int) predraw; /* predraw... */ + void(NSClientPlayer) postdraw; /* postdraw... */ - int(player) isempty; /* kinda handy */ - void(player, int, vector, float) hudpic; + int(NSClientPlayer) isempty; /* kinda handy */ + void(NSClientPlayer, int, vector, float) hudpic; } weapon_t; -void Weapons_Holster(player pl); -void Weapons_Primary(player pl); -void Weapons_Secondary(player pl); -void Weapons_Reload(player pl); -void Weapons_Release(player pl); -void Weapons_PreDraw(player pl, int); +void Weapons_Init(void); +void Weapons_Draw(NSClientPlayer pl); +void Weapons_Holster(NSClientPlayer pl); +void Weapons_Primary(NSClientPlayer pl); +void Weapons_Secondary(NSClientPlayer pl); +void Weapons_Reload(NSClientPlayer pl); +void Weapons_Release(NSClientPlayer pl); +void Weapons_PreDraw(NSClientPlayer pl, int); -float Weapons_GetAim(player, int); -int Weapons_IsEmpty(player, int); -void Weapons_DrawCrosshair(player pl); -void Weapons_MakeVectors(player pl); -vector Weapons_GetCameraPos(player pl); -void Weapons_ViewAnimation(player pl, int); -void Weapons_ViewPunchAngle(player pl, vector); -int Weapons_IsPresent(player, int); -void Weapons_UpdateAmmo(player, int, int, int); -int Weapons_GetAnimation(player pl); +float Weapons_GetAim(NSClientPlayer, int); +int Weapons_IsEmpty(NSClientPlayer, int); +void Weapons_DrawCrosshair(NSClientPlayer pl); +void Weapons_MakeVectors(NSClientPlayer pl); +vector Weapons_GetCameraPos(NSClientPlayer pl); +void Weapons_ViewAnimation(NSClientPlayer pl, int); +void Weapons_ViewPunchAngle(NSClientPlayer pl, vector); +int Weapons_IsPresent(NSClientPlayer, int); +void Weapons_UpdateAmmo(NSClientPlayer, int, int, int); +int Weapons_GetAnimation(NSClientPlayer pl); void Weapons_EnableModel(void); void Weapons_DisableModel(void); -weapontype_t Weapons_GetType(player, int); +weapontype_t Weapons_GetType(NSClientPlayer, int); void Weapons_SetLeftModel(string); void Weapons_SetRightModel(string); @@ -90,10 +92,11 @@ void Weapons_SetGeomset(string); void Weapons_SetModel(string); void Weapons_Sound(entity, float, string); +string Weapons_GetWorldmodel(int); #ifdef CLIENT -string Weapons_GetPlayermodel(player, int); -void Weapons_HUDPic(player, int, int, vector, float); +string Weapons_GetPlayermodel(NSClientPlayer, int); +void Weapons_HUDPic(NSClientPlayer, int, int, vector, float); #endif #else #endif \ No newline at end of file diff --git a/base/src/shared/weapon_common.qc b/src/shared/weapon_common.qc similarity index 88% rename from base/src/shared/weapon_common.qc rename to src/shared/weapon_common.qc index 154aba0b..000ec6b0 100644 --- a/base/src/shared/weapon_common.qc +++ b/src/shared/weapon_common.qc @@ -15,7 +15,6 @@ */ #ifndef NEW_INVENTORY -var int g_weapon_weights[g_weapons.length]; #ifdef CLIENT var int g_weapon_order[g_weapons.length]; @@ -165,16 +164,21 @@ Weapons_SetGeomset(string set) } void -Weapons_Draw(player pl) +Weapons_Draw(NSClientPlayer pl) { int i = pl.activeweapon; /* In case the previous weapon hid the model */ Weapons_EnableModel(); +#ifdef CLIENT + View_SetMuzzleflash(0); +#endif + pl.w_attack_next = 0.5f; pl.w_idle_next = 2.5f; pl.viewzoom = 1.0f; + pl.weapontime = 0.0f; /* we're meant to respawn when we're dead, don't unset! */ if (pl.health > 0) { @@ -195,7 +199,7 @@ Weapons_Draw(player pl) } void -Weapons_Holster(player pl) +Weapons_Holster(NSClientPlayer pl) { int i = pl.activeweapon; @@ -204,7 +208,7 @@ Weapons_Holster(player pl) } void -Weapons_Primary(player pl) +Weapons_Primary(NSClientPlayer pl) { int i = pl.activeweapon; @@ -221,7 +225,7 @@ Weapons_Primary(player pl) void Weapons_AmmoUpdate(entity target) { - player pl = (player)target; + NSClientPlayer pl = (NSClientPlayer)target; int i = pl.activeweapon; if (g_weapons[i].updateammo != __NULL__) @@ -230,7 +234,7 @@ Weapons_AmmoUpdate(entity target) } void -Weapons_Secondary(player pl) +Weapons_Secondary(NSClientPlayer pl) { int i = pl.activeweapon; @@ -242,7 +246,7 @@ Weapons_Secondary(player pl) } void -Weapons_Reload(player pl) +Weapons_Reload(NSClientPlayer pl) { int i = pl.activeweapon; @@ -254,7 +258,7 @@ Weapons_Reload(player pl) } void -Weapons_Release(player pl) +Weapons_Release(NSClientPlayer pl) { int i = pl.activeweapon; @@ -265,7 +269,7 @@ Weapons_Release(player pl) } void -Weapons_PreDraw(player pl, int thirdperson) +Weapons_PreDraw(NSClientPlayer pl, int thirdperson) { int i = pl.activeweapon; @@ -274,7 +278,7 @@ Weapons_PreDraw(player pl, int thirdperson) } int -Weapons_IsEmpty(player pl, int w) +Weapons_IsEmpty(NSClientPlayer pl, int w) { int r = 0; @@ -291,7 +295,7 @@ Weapons_IsEmpty(player pl, int w) weapontype_t -Weapons_GetType(player pl, int w) +Weapons_GetType(NSClientPlayer pl, int w) { weapontype_t r = WPNTYPE_INVALID; @@ -307,7 +311,7 @@ Weapons_GetType(player pl, int w) } void -Weapons_DrawCrosshair(player pl) +Weapons_DrawCrosshair(NSClientPlayer pl) { int i = pl.activeweapon; @@ -325,7 +329,7 @@ Weapons_GetWorldmodel(int id) } string -Weapons_GetPlayermodel(player pl, int id) +Weapons_GetPlayermodel(NSClientPlayer pl, int id) { if (g_weapons[id].pmodel != __NULL__) return g_weapons[id].pmodel(pl); @@ -343,7 +347,7 @@ Weapons_GetDeathmessage(int id) } float -Weapons_GetAim(player pl, int id) +Weapons_GetAim(NSClientPlayer pl, int id) { if (g_weapons[id].aimanim != __NULL__) return g_weapons[id].aimanim(pl); @@ -353,7 +357,7 @@ Weapons_GetAim(player pl, int id) #ifdef CLIENT void -Weapons_HUDPic(player pl, int id, int s, vector pos, float a) +Weapons_HUDPic(NSClientPlayer pl, int id, int s, vector pos, float a) { if (g_weapons[id].hudpic != __NULL__) g_weapons[id].hudpic(pl, s, pos, a); @@ -361,7 +365,7 @@ Weapons_HUDPic(player pl, int id, int s, vector pos, float a) #endif void -Weapons_MakeVectors(player pl) +Weapons_MakeVectors(NSClientPlayer pl) { #ifdef SERVER makevectors(pl.v_angle); @@ -371,7 +375,7 @@ Weapons_MakeVectors(player pl) } vector -Weapons_GetCameraPos(player pl) +Weapons_GetCameraPos(NSClientPlayer pl) { #ifdef SERVER return (pl.origin + pl.view_ofs); @@ -381,11 +385,8 @@ Weapons_GetCameraPos(player pl) } void -Weapons_ViewAnimation(player pl, int i) +Weapons_ViewAnimation(NSClientPlayer pl, int i) { -#if 0 - View_PlayAnimation(i); -#endif pl.weaponframe = i; pl.weapontime = 0.0f; } @@ -395,19 +396,19 @@ int View_GetAnimation(void); #endif int -Weapons_GetAnimation(player pl) +Weapons_GetAnimation(NSClientPlayer pl) { return pl.weaponframe; } void -Weapons_ViewPunchAngle(player pl, vector add) +Weapons_ViewPunchAngle(NSClientPlayer pl, vector add) { pl.punchangle += add; } int -Weapons_IsPresent(player pl, int w) +Weapons_IsPresent(NSClientPlayer pl, int w) { if (pl.g_items & g_weapons[w].id) { return (1); @@ -440,7 +441,7 @@ Sets .a_ammoX fields and clamps them so they can be networked as a single byte. ================= */ void -Weapons_UpdateAmmo(player pl, int a1, int a2, int a3) +Weapons_UpdateAmmo(NSClientPlayer pl, int a1, int a2, int a3) { /* no change */ if (a1 == -1) diff --git a/src/shared/weapons.h b/src/shared/weapons.h index 7b6767f6..5a54f5d1 100644 --- a/src/shared/weapons.h +++ b/src/shared/weapons.h @@ -35,4 +35,7 @@ Weapons_SwitchBest(NSClientPlayer pl, optional float skip) { } -#endif \ No newline at end of file +#endif + + +var int g_weapon_weights[32]; \ No newline at end of file