diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..90cbab7
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,114 @@
+name: Build
+
+on: ["push", "workflow_dispatch"]
+
+jobs:
+ build_main:
+ name: Build for ${{ matrix.os_short }}
+ runs-on: ${{ matrix.os_version }}
+
+ # skip build on '[ci skip]'
+ if: "!contains(github.event.head_commit.message, '[ci skip]')"
+
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - ubuntu-22.04
+ - windows-x32
+ include:
+ - os: ubuntu-22.04
+ os_short: linux
+ os_version: ubuntu-22.04
+ package_ext: tar.gz
+ dbg_ext: dbg
+ cc: clang
+ cxx: clang++
+ vs_arch: unused
+ am_arch: x86
+
+ - os: windows-x32
+ os_short: win32
+ os_version: windows-latest
+ package_ext: zip
+ dbg_ext: pdb
+ cc: not-used
+ cxx: not-used
+ vs_arch: x32
+ am_arch: x86
+
+
+ steps:
+ - name: Install (Linux)
+ if: runner.os == 'Linux'
+ run: |
+ sudo dpkg --add-architecture i386
+ sudo apt-get update
+ sudo apt-get install -y clang g++-multilib
+ echo "CC=clang" >> $GITHUB_ENV
+ echo "CXX=clang++" >> $GITHUB_ENV
+
+ - name: Add msbuild to PATH (Windows)
+ if: runner.os == 'Windows'
+ uses: microsoft/setup-msbuild@v2
+
+ - name: Install (Windows)
+ if: runner.os == 'Windows'
+ shell: cmd
+ run: |
+ :: See https://github.com/microsoft/vswhere/wiki/Find-VC
+ for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
+ call "%%i"\Common7\Tools\vsdevcmd.bat -arch=${{ matrix.vs_arch }} -host_arch=x64
+ )
+
+ :: Loop over all environment variables and make them global.
+ for /f "delims== tokens=1,2" %%a in ('set') do (
+ echo>>"%GITHUB_ENV%" %%a=%%b
+ )
+
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.12'
+
+ - name: Setup ambuild
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install wheel
+ pip install git+https://github.com/alliedmodders/ambuild
+
+ - name: Fetch RealBot
+ uses: actions/checkout@v4
+ with:
+ path: realbot
+ submodules: recursive
+
+ - name: Build Files
+ shell: bash
+ working-directory: realbot
+ run: |
+ mkdir post
+ cd post
+
+ export AM_ARCH=${{ matrix.am_arch }}
+
+ python3 ../configure.py --symbol-files --enable-optimize
+
+ ambuild
+
+ - uses: benjlevesque/short-sha@v2.2
+ id: short-sha
+
+ - name: Upload Binary
+ uses: actions/upload-artifact@v4
+ with:
+ name: realbot-${{ matrix.os_short }}-${{ steps.short-sha.outputs.sha }}
+ path: |
+ realbot/post/*
+
+ - name: Upload Debug Symbols
+ uses: actions/upload-artifact@v4
+ with:
+ name: realbot-dbgsym-${{ matrix.os_short }}-${{ steps.short-sha.outputs.sha }}
+ path: |
+ realbot/post/**/*.${{ matrix.dbg_ext }}
diff --git a/.gitignore b/.gitignore
index 2efd4e6..ab58d96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@
x64/
x86/
build/
+build_linux/
bld/
[Bb]in/
[Oo]bj/
@@ -216,3 +217,5 @@ CMakeLists.txt
cmake-build-debug/
*.o
+realbot_mm.so
+apg-load
diff --git a/AMBuildScript b/AMBuildScript
new file mode 100644
index 0000000..a5d68dd
--- /dev/null
+++ b/AMBuildScript
@@ -0,0 +1,161 @@
+# AMBuildScript for RealBot, written by Anonymous Player
+# vim: set sts=4 ts=8 sw=4 tw=99 et ft=python:
+import os, sys
+
+builder.cxx = builder.DetectCxx(target_arch = 'x86')
+
+# Include search paths
+include_paths = [
+ os.path.join(builder.currentSourcePath, 'dependencies', 'metamod-hl1', 'metamod'),
+ os.path.join(builder.currentSourcePath, 'dependencies', 'hlsdk', 'common'),
+ os.path.join(builder.currentSourcePath, 'dependencies', 'hlsdk', 'public'),
+ os.path.join(builder.currentSourcePath, 'dependencies', 'hlsdk', 'dlls'),
+ os.path.join(builder.currentSourcePath, 'dependencies', 'hlsdk', 'engine'),
+ os.path.join(builder.currentSourcePath, 'dependencies', 'hlsdk', 'game_shared'),
+ os.path.join(builder.currentSourcePath, 'dependencies', 'hlsdk', 'pm_shared'),
+]
+
+# Compiler setup
+builder.cxx.defines += [
+ 'HAVE_STDINT_H',
+ ]
+
+if builder.cxx.like('gcc'):
+ builder.cxx.defines += [
+ 'stricmp=strcasecmp',
+ 'strcmpi=strcasecmp'
+ ]
+
+ builder.cxx.c_only_flags += ['-std=gnu99']
+if builder.cxx.target.platform == 'linux':
+ # Linux defines
+ builder.cxx.defines += ['_LINUX', 'POSIX', 'LINUX', 'linux']
+ # Linux compiler C flags
+ builder.cxx.cflags += [
+ '-mtune=generic',
+ '-pipe',
+ '-fPIC',
+ '-msse4.2',
+ '-mfpmath=sse',
+ '-fno-strict-aliasing',
+ '-Wall',
+ '-Werror',
+ '-Wno-uninitialized',
+ '-Wno-unused',
+ '-Wno-switch',
+ '-Wno-format',
+ '-Wno-format-security',
+ '-Wno-unknown-attributes',
+ '-Wno-logical-op-parentheses',
+ '-Wno-return-stack-address',
+ '-m32',
+ ]
+ # Linux compiler C++ flags
+ builder.cxx.cxxflags += [
+ '-Wno-invalid-offsetof',
+ '-Wno-write-strings',
+ '-std=c++17',
+ ]
+ # Linux linker flags
+ builder.cxx.linkflags += ['-m32', '-ldl', '-lm', '-flto']
+elif builder.cxx.target.platform == 'windows':
+ # Windows defines
+ builder.cxx.defines += [
+ '_CRT_SECURE_NO_DEPRECATE',
+ '_CRT_SECURE_NO_WARNINGS',
+ '_CRT_NONSTDC_NO_DEPRECATE',
+ 'NOMINMAX',
+ 'WIN32',
+ '_WINDOWS'
+ ]
+ # Windows compiler C flags
+ builder.cxx.cflags += []
+ # Windows compiler C++ flags
+ builder.cxx.cxxflags += [
+ '/std:c++17',
+ '/arch:SSE2',
+ '/fp:precise',
+ '/Qspectre',
+ '/EHsc'
+ ]
+ # Windows linker flags
+ builder.cxx.linkflags += [
+ '/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1',
+ '/SECTION:.data,RW',
+ '/MACHINE:X86'
+ ]
+
+# Compiler options for optimization ( --enable-optimize )
+if builder.options.optimize:
+ # Shared optimization definitions
+ builder.cxx.defines += ['NDEBUG']
+ if builder.cxx.target.platform == 'linux':
+ # Linux optimization flags
+ builder.cxx.cflags += ['-O3']
+ # Linux optimization link flags #TODO
+ #builder.cxx.linkflags += ['-flto']
+ elif builder.cxx.target.platform == 'windows':
+ # Windows optimization flags - /Ob3 needs to be after /Ox, enables aggressive function inling -caxanga334
+ builder.cxx.cflags += ['/Ox', '/Zo', '/Ob3', '/GL']
+ # Windows optimization link flags
+ builder.cxx.linkflags += ['/OPT:ICF', '/OPT:REF', '/LTCG']
+ # This needs to be after our optimization flags which could otherwise disable it.
+ builder.cxx.cflags += ['/Oy-']
+
+# Compiler options for debugging ( --enable-debug )
+if builder.options.debug:
+ # Shared debug definitions
+ builder.cxx.defines += ['DEBUG', '_DEBUG']
+ if builder.cxx.target.platform == 'linux':
+ # Linux debug flags
+ builder.cxx.cflags += ['-g3', '-Og', '-ggdb3']
+ elif builder.cxx.target.platform == 'windows':
+ # Windows debug flags
+ builder.cxx.cflags += ['/Od', '/RTC1', '/MTd']
+ # Windows debug link flags
+ builder.cxx.linkflags += ['/NODEFAULTLIB:libcmt']
+
+# Handle --enable-static-lib and --enable-shared-lib
+if builder.cxx.target.platform == 'linux':
+ if builder.options.staticlib == '1':
+ builder.cxx.linkflags += [
+ '-static-libgcc',
+ '-static-libstdc++'
+ ]
+ elif builder.options.sharedlib == '1':
+ builder.cxx.linkflags += [
+ '-shared-libgcc',
+ ]
+
+library = builder.cxx.Library('realbot_mm')
+
+library.compiler.includes += include_paths
+
+library.sources += [
+ 'bot.cpp',
+ 'bot_buycode.cpp',
+ 'bot_client.cpp',
+ 'bot_func.cpp',
+ 'bot_navigate.cpp',
+ 'build.cpp',
+ 'ChatEngine.cpp',
+ 'dll.cpp',
+ 'engine.cpp',
+ 'game.cpp',
+ 'IniParser.cpp',
+ 'NodeMachine.cpp',
+ 'util.cpp',
+]
+
+#builder.RunBuildScripts(
+# [
+# 'Bsp2Rbn/AMBuilder',
+# ],
+# #{ 'AMXX': AMXX }
+#)
+
+#
+# Run scripts, add binaries
+#
+
+builder.Add(library)
\ No newline at end of file
diff --git a/Bsp2Rbn/AMBuilder b/Bsp2Rbn/AMBuilder
new file mode 100644
index 0000000..aec23f5
--- /dev/null
+++ b/Bsp2Rbn/AMBuilder
@@ -0,0 +1,24 @@
+# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
+import os.path
+
+#binary = AMXX.MetaModule(builder, 'bsp2rbn')
+
+binary.sources = [
+ '../../public/sdk/amxxmodule.cpp',
+ 'CRank.cpp',
+ 'CMisc.cpp',
+ 'NBase.cpp',
+ 'NRank.cpp',
+ 'usermsg.cpp',
+ 'Utils.cpp',
+ 'moduleconfig.cpp',
+]
+
+if builder.target_platform == 'windows':
+ #binary.sources += ['version.rc']
+ binary.compiler.linkflags += [
+ '/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1',
+ '/SECTION:.data,RW',
+ ]
+
+##AMXX.modules += [builder.Add(binary)]
diff --git a/Bsp2Rbn/Bsp2Rbn.sln b/Bsp2Rbn/Bsp2Rbn.sln
new file mode 100644
index 0000000..a9af632
--- /dev/null
+++ b/Bsp2Rbn/Bsp2Rbn.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32414.318
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Bsp2Rbn", "Bsp2Rbn.vcxproj", "{85813A68-52FB-4F75-91BA-DD3B6C50FD68}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Debug|x64.ActiveCfg = Debug|x64
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Debug|x64.Build.0 = Debug|x64
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Debug|x86.ActiveCfg = Debug|Win32
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Debug|x86.Build.0 = Debug|Win32
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Release|x64.ActiveCfg = Release|x64
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Release|x64.Build.0 = Release|x64
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Release|x86.ActiveCfg = Release|Win32
+ {85813A68-52FB-4F75-91BA-DD3B6C50FD68}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E7378DCB-1E54-43A4-B950-59F6E738F898}
+ EndGlobalSection
+EndGlobal
diff --git a/Bsp2Rbn/Bsp2Rbn.vcxproj b/Bsp2Rbn/Bsp2Rbn.vcxproj
new file mode 100644
index 0000000..0c9f2ae
--- /dev/null
+++ b/Bsp2Rbn/Bsp2Rbn.vcxproj
@@ -0,0 +1,176 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 16.0
+ Win32Proj
+ {85813a68-52fb-4f75-91ba-dd3b6c50fd68}
+ Bsp2Rbn
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v120
+ false
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+ ..\;..\dependencies\metamod-hl1\metamod;..\dependencies\hlsdk\common;..\dependencies\hlsdk\engine;..\dependencies\hlsdk\dlls;..\dependencies\hlsdk\pm_shared;..\dependencies\hlsdk\public;%(AdditionalIncludeDirectories)
+ Default
+
+
+ Console
+ false
+ true
+ true
+ false
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+ ..\;..\dependencies\metamod-hl1\metamod;..\dependencies\hlsdk\common;..\dependencies\hlsdk\engine;..\dependencies\hlsdk\dlls;..\dependencies\hlsdk\pm_shared;..\dependencies\hlsdk\public;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bsp2Rbn/Bsp2Rbn.vcxproj.filters b/Bsp2Rbn/Bsp2Rbn.vcxproj.filters
new file mode 100644
index 0000000..c6780bb
--- /dev/null
+++ b/Bsp2Rbn/Bsp2Rbn.vcxproj.filters
@@ -0,0 +1,87 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/Bsp2Rbn/DrawNodes.c b/Bsp2Rbn/DrawNodes.c
index 1d0cd1c..526f196 100644
--- a/Bsp2Rbn/DrawNodes.c
+++ b/Bsp2Rbn/DrawNodes.c
@@ -1,464 +1,464 @@
-// Based on Pierre-Marie Batty bmpfile.cpp
-
-// Tuned for Realbot .RBN files by evyncke@students.hec.be, June 2004
-
-// RACC - AI development project for first-person shooter games derived from Valve's Half-Life
-// (http://www.racc-ai.com/)
-//
-// The game to engine interfacing code is based on the work done by Jeffrey 'botman' Broome
-// (http://planethalflife.com/botman/)
-//
-// This project is partially based on the work done by Eric Bieschke in his BSDbot
-// (http://gamershomepage.com/csbot/)
-//
-// This project is partially based on the work done by Brendan "Spyro" McCarthy in his ODD Bot
-// (http://oddbot.hlfusion.com/)
-//
-// This project is partially based on the work done by Alistair 'eLiTe' Stewart in his TEAMbot
-// (http://www.planethalflife.com/teambot/)
-//
-// The BMP writing functions in this file come primarily from botman's BSP slicer utility
-// (http://planethalflife.com/botman/)
-//
-// Rational Autonomous Cybernetic Commandos AI
-//
-// bmpfile.cpp
-//
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-extern char * Version ;
-
-// width and height of the debug bitmap image
-#define DEBUG_BMP_WIDTH 2048
-#define DEBUG_BMP_HEIGHT 2048
-
-float scalex, scaley, scale;
-char *bmp_buffer;
-
-#include "../bot.h"
-#include "../NodeMachine.h"
-
-extern char * Version ;
-
-/* Copy from NodeMachine.cpp by Stefan Hendricks */
-
-tNode Nodes[MAX_NODES]; // Nodes
-tInfoNode InfoNodes[MAX_NODES]; // Info for Nodes
-tMeredian Meredians[MAX_MEREDIANS][MAX_MEREDIANS]; // Meredian lookup search for Nodes
-int iMaxUsedNodes;
-float maxx, maxy, minx, miny ;
-
-void load (char * mapname)
-{
- char filename[256];
- int i, n;
-
- // Set Directory name
- strcpy (filename, mapname);
- strcat (filename, ".rbn"); // nodes file
-
- FILE *rbl;
- rbl = fopen (filename, "rb");
-
- if (rbl != NULL)
- {
- int iVersion ;
- fread (&iVersion, sizeof (int), 1, rbl);
-
- // Version 1.0
- if (iVersion == FILE_NODE_VER1)
- {
- for (i = 0; i < MAX_NODES; i++)
- {
- fread (&Nodes[i].origin, sizeof (Vector), 1, rbl);
- for (n = 0; n < MAX_NEIGHBOURS; n++)
- {
- fread (&Nodes[i].iNeighbour[n], sizeof (int), 1, rbl);
- }
-
- // save bit flags
- fread (&Nodes[i].iNodeBits, sizeof (int), 1, rbl);
-
- if (Nodes[i].origin != Vector (9999, 9999, 9999))
- iMaxUsedNodes = i;
- }
- }
- } else {
- fprintf(stderr,"Cannot open file %s\n",filename) ;
- exit ;
- }
- printf("%d nodes loaded out of %d.\n",iMaxUsedNodes,MAX_NODES) ;
-}
-
-void InitDebugBitmap (void)
-{
- // this function allocates memory and clears the debug bitmap buffer
-
- if (bmp_buffer)
- free (bmp_buffer); // reliability check, free BMP buffer if already allocated
- bmp_buffer = NULL;
- bmp_buffer = (char *) malloc (DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT); // allocate memory
- if (bmp_buffer == NULL) {
- fprintf (stderr,"InitDebugBitmap(): unable to allocate %d kbytes for BMP buffer!\n", DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT / 1024);
- exit(1) ;
- }
-
- memset (bmp_buffer, 14, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT); // Set all to white
- return; // yes, it's as simple as that
-}
-
-
-void DrawPoint (const Vector v, unsigned char color)
-{
- int offset, fraction, x0, y0;
- float scalex, scaley, scale;
-
- if (bmp_buffer == NULL)
- {
- fprintf (stderr,"DrawLineInDebugBitmap(): function called with NULL BMP buffer!\n");
- return; // reliability check: cancel if bmp buffer unallocated
- }
-
- // first compute the X and Y divider scale, and take the greatest of both
- scalex = (maxx - minx) / DEBUG_BMP_WIDTH ;
- scaley = (maxy - miny) / DEBUG_BMP_WIDTH ;
- if (scalex > scaley)
- scale = scalex + scalex / 100; // add a little offset (margin) for safety
- else
- scale = scaley + scaley / 100; // add a little offset (margin) for safety
-
- // translate the world coordinates in image pixel coordinates
- x0 = (int) ((v.x - minx) / scale);
- y0 = (int) ((v.y - miny) / scale);
-
- offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf( stderr,"DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1) ;
- }
-
- bmp_buffer[offset] = color; // draw the point itself
- if (offset+1 < DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) bmp_buffer[offset+1] = color; // make a small star on the right
- if (offset-1 >= 0) bmp_buffer[offset-1] = color; // make a small star on the left
- if (offset+DEBUG_BMP_WIDTH < DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) bmp_buffer[offset+DEBUG_BMP_WIDTH] = color;
- if (offset-DEBUG_BMP_WIDTH >= 0) bmp_buffer[offset-DEBUG_BMP_WIDTH] = color; // make a small star above
-}
-
-void DrawLineInDebugBitmap (const Vector v_from, const Vector v_to, unsigned char color)
-{
- // blind copy of botman's Bresenham(). This function prints a vector line into a bitmap dot
- // matrix. The dot matrix (bmp_buffer) is a global array. The size of the bitmap is always
- // assumed to be DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT pixels (currently 2000 * 2000 to fit with
- // the size of the universe, with an adaptative unit scale, up to 1 pixel = 10 vector units).
-
- int x0, y0, x1, y1;
- int dx, stepx, dy, stepy;
- int offset, fraction;
-
- if (bmp_buffer == NULL)
- {
- fprintf (stderr,"DrawLineInDebugBitmap(): function called with NULL BMP buffer!\n");
- return; // reliability check: cancel if bmp buffer unallocated
- }
-
- // translate the world coordinates in image pixel coordinates
- x0 = (int) ((v_from.x - minx) / scale);
- y0 = (int) ((v_from.y - miny) / scale);
- x1 = (int) ((v_to.x - minx) / scale);
- y1 = (int) ((v_to.y - miny) / scale);
-
- dx = (x1 - x0) * 2;
- dy = (y1 - y0) * 2;
- if (dx < 0) { dx = -dx; stepx = -1; } else stepx = 1;
- if (dy < 0) { dy = -dy; stepy = -1; } else stepy = 1;
-
- offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf( stderr,"DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1) ;
- }
-
- bmp_buffer[offset] = color; // draw the first point of the line
-
- // is the line rather horizontal than vertical ? We need to know this to determine the step
- // advance in the Bresenham grid, either we draw y = f(x), or x = f(y).
- if (dx > dy)
- {
- // the line is rather horizontal, we can draw it safely for incremental values of x
-
- fraction = 2 * dy - dx; // fraction of height in x0 pixel's 'square' where y0 should be
-
- // while we've not reached the end of the segment...
- while (x0 != x1)
- {
- // if y0 should rather be drawn on a different height than its previous height...
- if (fraction >= 0)
- {
- y0 += stepy; // draw it one pixel aside, then (depending on line orientation)
- fraction -= 2 * dx; // and reset its fraction (Bresenham, not sure I get the math)
- }
- x0 += stepx; // in either case, draw x0 one pixel aside its previous position
- fraction += 2 * dy; // and update y0's fraction (not sure I get the math - but whatever)
-
- // compute the offset in the BMP buffer corresponding to this point
- offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf(stderr, "DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1) ;
- }
-
- bmp_buffer[offset] = color; // set this point to have the specified color
- }
- }
- else
- {
- // else the line is rather vertical, we NEED to draw it for incremental values of y (if we
- // did it for incremental values of x instead, we would drop half the pixels).
-
- fraction = 2 * dx - dy; // fraction of width in y0 pixel's 'square' where x0 should be
-
- // while we've not reached the end of the segment...
- while (y0 != y1)
- {
- // if x0 should rather be drawn on a different width than its previous width...
- if (fraction >= 0)
- {
- x0 += stepx; // draw it one pixel aside, then (depending on line orientation)
- fraction -= 2 * dy; // and reset its fraction (Bresenham, not sure I get the math)
- }
- y0 += stepy; // in either case, draw y0 one pixel aside its previous position
- fraction += 2 * dx; // and update x0's fraction (not sure I get the math - but whatever)
-
- // compute the offset in the BMP buffer corresponding to this point
- offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf (stderr,"DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1) ;
- }
- bmp_buffer[offset] = color; // set this point to have the specified color
- }
- }
-
- return; // finished, segment has been printed into the BMP dot matrix
-}
-
-
-void WriteDebugBitmap (const char *mapname)
-{
- // this function writes the debug bitmap image buffer in a .BMP file to disk. The format is
- // 256 color and 2000 * 2000 pixels. The center of the world being roughly the center of the
- // bitmap. The bitmap is stored in the file specified by 'filename' (which can be a relative
- // path from the Half-Life base directory).
- char filename[256];
- FILE *fp;
- int data_start, file_size;
- unsigned long dummy;
-
- if (bmp_buffer == NULL)
- {
- fprintf (stderr,"WriteDebugBitmap(): function called with NULL BMP buffer!\n");
- return; // reliability check: cancel if bmp buffer unallocated
- }
-
- // open (or create) the .bmp file for writing in binary mode...
- // Set Directory name
-// strcpy (filename, "data/cstrike/maps/");
- strcpy (filename, mapname);
- strcat (filename, ".bmp"); // bitmap file
- fp = fopen (filename, "wb");
- if (fp == NULL)
- {
- fprintf (stderr,"RACC: WriteDebugBitmap(): unable to open BMP file!\n");
- if (bmp_buffer)
- free (bmp_buffer); // cannot open file, free DXF buffer
- bmp_buffer = NULL;
- return; // cancel if error creating file
- }
-
- // write the BMP header
- fwrite ("BM", 2, 1, fp); // write the BMP header tag
- fseek (fp, sizeof (unsigned long), SEEK_CUR); // skip the file size field (will write it last)
- fwrite ("\0\0", sizeof (short), 1, fp); // dump zeros in the first reserved field (unused)
- fwrite ("\0\0", sizeof (short), 1, fp); // dump zeros in the second reserved field (unused)
- fseek (fp, sizeof (unsigned long), SEEK_CUR); // skip the data start field (will write it last)
-
- // write the info header
- dummy = 40;
- fwrite (&dummy, sizeof (unsigned long), 1, fp); // write the info header size (does 40 bytes)
- dummy = DEBUG_BMP_WIDTH;
- fwrite (&dummy, sizeof (long), 1, fp); // write the image width (2000 px)
- dummy = DEBUG_BMP_HEIGHT;
- fwrite (&dummy, sizeof (long), 1, fp); // write the image height (2000 px)
- dummy = 1;
- fwrite (&dummy, sizeof (short), 1, fp); // write the # of planes (1)
- dummy = 8;
- fwrite (&dummy, sizeof (short), 1, fp); // write the bit count (8)
- dummy = 0;
- fwrite (&dummy, sizeof (unsigned long), 1, fp); // write the compression id (no compression)
- dummy = DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT;
- fwrite (&dummy, sizeof (unsigned long), 1, fp); // write the image size (2000 * 2000)
- dummy = 0;
- fwrite (&dummy, sizeof (long), 1, fp); // write the X pixels per meter (not specified)
- fwrite (&dummy, sizeof (long), 1, fp); // write the Y pixels per meter (not specified)
- dummy = 256;
- fwrite (&dummy, sizeof (unsigned long), 1, fp); // write the # of colors used (all)
- fwrite (&dummy, sizeof (unsigned long), 1, fp); // write the # of important colors (wtf ?)
-
- // write the color palette (R, G, B, reserved byte)
- fputc (0x00, fp); fputc (0x00, fp); fputc (0x00, fp); fputc (0x00, fp); // 0=BLACK
- fputc (0xFF, fp); fputc (0xFF, fp); fputc (0xFF, fp); fputc (0x00, fp); // 1=WHITE
- fputc (0x80, fp); fputc (0x80, fp); fputc (0x80, fp); fputc (0x00, fp); // 2=GREY
- fputc (0xC0, fp); fputc (0xC0, fp); fputc (0xC0, fp); fputc (0x00, fp); // 3=SILVER
- fputc (0x80, fp); fputc (0x00, fp); fputc (0x00, fp); fputc (0x00, fp); // 4=DARK RED
- fputc (0xFF, fp); fputc (0x00, fp); fputc (0x00, fp); fputc (0x00, fp); // 5=RED
- fputc (0x80, fp); fputc (0x80, fp); fputc (0x00, fp); fputc (0x00, fp); // 6=DARK YELLOW
- fputc (0xFF, fp); fputc (0xFF, fp); fputc (0x00, fp); fputc (0x00, fp); // 7=YELLOW
- fputc (0x00, fp); fputc (0x80, fp); fputc (0x00, fp); fputc (0x00, fp); // 8=DARK GREEN
- fputc (0x00, fp); fputc (0xFF, fp); fputc (0x00, fp); fputc (0x00, fp); // 9=GREEN
- fputc (0x00, fp); fputc (0x00, fp); fputc (0x80, fp); fputc (0x00, fp); // 10=DARK BLUE
- fputc (0x00, fp); fputc (0x00, fp); fputc (0x80, fp); fputc (0x00, fp); // 11=BLUE
- fputc (0x80, fp); fputc (0x00, fp); fputc (0x80, fp); fputc (0x00, fp); // 12=DARK PURPLE
- fputc (0x80, fp); fputc (0x00, fp); fputc (0x80, fp); fputc (0x00, fp); // 13=PURPLE
- fputc (0xFF, fp); fputc (0xFF, fp); fputc (0xFF, fp); fputc (0x00, fp); // 14=WHITE
- fputc (0xEF, fp); fputc (0xEF, fp); fputc (0xEF, fp); fputc (0x00, fp); // 15=WHITE-GREY
- fputc (0xDF, fp); fputc (0xDF, fp); fputc (0xDF, fp); fputc (0x00, fp); // 16=GREY
- fputc (0xCF, fp); fputc (0xCF, fp); fputc (0xCF, fp); fputc (0x00, fp); // 17=DARKGREY
- fputc (0xBF, fp); fputc (0xBF, fp); fputc (0xBF, fp); fputc (0x00, fp); // 18=DARKGREY
- fputc (0xAF, fp); fputc (0xAF, fp); fputc (0xAF, fp); fputc (0x00, fp); // 19=DARKGREY
-
- for (dummy = 20; dummy < 256; dummy++)
- {
- // fill out the rest of the palette with zeros
- fputc (0x00, fp); fputc (0x00, fp); fputc (0x00, fp); fputc (0x00, fp);
- }
-
- // write the actual image data
- data_start = ftell (fp); // get the data start position (that's where we are now)
- fwrite (bmp_buffer, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT, 1, fp); // write the image
- file_size = ftell (fp); // get the file size now that the image is dumped
-
- // now that we've dumped our data, we know the file size and the data start position
-
- fseek (fp, 0, SEEK_SET); // rewind
- fseek (fp, 2, SEEK_CUR); // skip the BMP header tag "BM"
- fwrite (&file_size, sizeof (unsigned long), 1, fp); // write the file size at its location
- fseek (fp, sizeof (short), SEEK_CUR); // skip the first reserved field
- fseek (fp, sizeof (short), SEEK_CUR); // skip the second reserved field
- fwrite (&data_start, sizeof (unsigned long), 1, fp); // write the data start at its location
-
- fclose (fp); // finished, close the BMP file
-
- if (bmp_buffer)
- free (bmp_buffer); // and free the BMP buffer
- bmp_buffer = NULL;
-
- return; // and return
-}
-
-void FindMinMax(void)
-{
- int i ;
-
- minx = miny = 9999.0 ;
- maxx = maxy = -9999.0 ;
- for (i=0; i maxx) maxx = Nodes[i].origin.x ;
- if (Nodes[i].origin.y > maxy) maxy = Nodes[i].origin.y ;
- if (Nodes[i].origin.x < minx) minx = Nodes[i].origin.x ;
- if (Nodes[i].origin.y < miny) miny = Nodes[i].origin.y ;
- }
-
- // Add some margin
- minx -= 32 ;
- miny -= 32 ;
- maxx += 32 ;
- maxy += 32 ;
- // first compute the X and Y divider scale, and take the greatest of both
- scalex = (maxx - minx) / DEBUG_BMP_WIDTH ;
- scaley = (maxy - miny) / DEBUG_BMP_HEIGHT ;
- if (scalex > scaley)
- scale = scalex + scalex / 100; // add a little offset (margin) for safety
- else
- scale = scaley + scaley / 100; // add a little offset (margin) for safety
-}
-
-// Mark meridians as slighly darker in alternance
-
-void MarkAxis(void)
-{
- int x, y, x0, y0 ;
-
- x0 = (int) ((0 - minx) / scale);
- y0 = (int) ((0 - miny) / scale);
-
- // Mark X axis by keeping X to 0 and varying Y
- if ((minx < 0) && (0 < maxx))
- for (y=0; y < DEBUG_BMP_HEIGHT ; y ++)
- bmp_buffer[y*DEBUG_BMP_WIDTH+x0]+=2 ;
-
- // Mar
- if ((miny < 0) && (0 < maxy))
- for (x=0; x < DEBUG_BMP_WIDTH; x++)
- bmp_buffer[y0*DEBUG_BMP_WIDTH+x]+=2 ;
-}
-
-void MarkMeredians(void)
-{
- int x, y ;
- int Meredian ;
-
- // Mark some meredians
- for (x=0; x < DEBUG_BMP_WIDTH; x++) {
- Meredian = abs(((float) x * scale + minx + 8192.0) / (float) SIZE_MEREDIAN) ;
- if (Meredian & 0x01) {
- for (y=0; y < DEBUG_BMP_HEIGHT ; y ++)
- bmp_buffer[y*DEBUG_BMP_WIDTH+x]++ ;
- }
- }
-
- // Mark some meredians
- for (y=0; y < DEBUG_BMP_HEIGHT; y++) {
- Meredian = abs(((float) y * scale + miny + 8192.0) / (float) SIZE_MEREDIAN) ;
- if (Meredian & 0x01) {
- for (x=0; x < DEBUG_BMP_HEIGHT ; x ++)
- bmp_buffer[y*DEBUG_BMP_WIDTH+x]++ ;
- }
- }
-}
-
-void PlotNodes(void)
-{
- int i, j ;
-
- for (i=0; i = 0) ; j++)
- DrawLineInDebugBitmap(Nodes[i].origin,
- Nodes[Nodes[i].iNeighbour[j]].origin,0) ;
- for (i=0; i
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern char* Version;
+
+// width and height of the debug bitmap image
+#define DEBUG_BMP_WIDTH 2048
+#define DEBUG_BMP_HEIGHT 2048
+
+float scalex, scaley, scale;
+char* bmp_buffer;
+
+#include "../bot.h"
+#include "../NodeMachine.h"
+
+extern char* Version;
+
+/* Copy from NodeMachine.cpp by Stefan Hendricks */
+
+tNode Nodes[MAX_NODES]; // Nodes
+tInfoNode InfoNodes[MAX_NODES]; // Info for Nodes
+tMeredian Meredians[MAX_MEREDIANS][MAX_MEREDIANS]; // Meredian lookup search for Nodes
+int iMaxUsedNodes;
+float maxx, maxy, minx, miny;
+
+void load(char* mapname)
+{
+ char filename[256];
+ int i, n;
+
+ // Set Directory name
+ strcpy(filename, mapname);
+ strcat(filename, ".rbn"); // nodes file
+
+ FILE* rbl;
+ rbl = fopen(filename, "rb");
+
+ if (rbl != NULL)
+ {
+ int iVersion;
+ fread(&iVersion, sizeof(int), 1, rbl);
+
+ // Version 1.0
+ if (iVersion == FILE_NODE_VER1)
+ {
+ for (i = 0; i < MAX_NODES; i++)
+ {
+ fread(&Nodes[i].origin, sizeof(Vector), 1, rbl);
+ for (n = 0; n < MAX_NEIGHBOURS; n++)
+ {
+ fread(&Nodes[i].iNeighbour[n], sizeof(int), 1, rbl);
+ }
+
+ // save bit flags
+ fread(&Nodes[i].iNodeBits, sizeof(int), 1, rbl);
+
+ if (Nodes[i].origin != Vector(9999, 9999, 9999))
+ iMaxUsedNodes = i;
+ }
+ }
+ }
+ else {
+ fprintf(stderr, "Cannot open file %s\n", filename);
+ exit;
+ }
+ printf("%d nodes loaded out of %d.\n", iMaxUsedNodes, MAX_NODES);
+}
+
+void InitDebugBitmap(void)
+{
+ // this function allocates memory and clears the debug bitmap buffer
+
+ if (bmp_buffer)
+ free(bmp_buffer); // reliability check, free BMP buffer if already allocated
+ bmp_buffer = NULL;
+ bmp_buffer = (char*)malloc(DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT); // allocate memory
+ if (bmp_buffer == NULL) {
+ fprintf(stderr, "InitDebugBitmap(): unable to allocate %d kbytes for BMP buffer!\n", DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT / 1024);
+ exit(1);
+ }
+
+ memset(bmp_buffer, 14, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT); // Set all to white
+ return; // yes, it's as simple as that
+}
+
+void DrawPoint(const Vector v, unsigned char color)
+{
+ int offset, fraction, x0, y0;
+ float scalex, scaley, scale;
+
+ if (bmp_buffer == NULL)
+ {
+ fprintf(stderr, "DrawLineInDebugBitmap(): function called with NULL BMP buffer!\n");
+ return; // reliability check: cancel if bmp buffer unallocated
+ }
+
+ // first compute the X and Y divider scale, and take the greatest of both
+ scalex = (maxx - minx) / DEBUG_BMP_WIDTH;
+ scaley = (maxy - miny) / DEBUG_BMP_WIDTH;
+ if (scalex > scaley)
+ scale = scalex + scalex / 100; // add a little offset (margin) for safety
+ else
+ scale = scaley + scaley / 100; // add a little offset (margin) for safety
+
+ // translate the world coordinates in image pixel coordinates
+ x0 = (int)((v.x - minx) / scale);
+ y0 = (int)((v.y - miny) / scale);
+
+ offset = y0 * DEBUG_BMP_WIDTH + x0;
+ if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
+ fprintf(stderr, "DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
+ exit(1);
+ }
+
+ bmp_buffer[offset] = color; // draw the point itself
+ if (offset + 1 < DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) bmp_buffer[offset + 1] = color; // make a small star on the right
+ if (offset - 1 >= 0) bmp_buffer[offset - 1] = color; // make a small star on the left
+ if (offset + DEBUG_BMP_WIDTH < DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) bmp_buffer[offset + DEBUG_BMP_WIDTH] = color;
+ if (offset - DEBUG_BMP_WIDTH >= 0) bmp_buffer[offset - DEBUG_BMP_WIDTH] = color; // make a small star above
+}
+
+void DrawLineInDebugBitmap(const Vector v_from, const Vector v_to, unsigned char color)
+{
+ // blind copy of botman's Bresenham(). This function prints a vector line into a bitmap dot
+ // matrix. The dot matrix (bmp_buffer) is a global array. The size of the bitmap is always
+ // assumed to be DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT pixels (currently 2000 * 2000 to fit with
+ // the size of the universe, with an adaptative unit scale, up to 1 pixel = 10 vector units).
+
+ int x0, y0, x1, y1;
+ int dx, stepx, dy, stepy;
+ int offset, fraction;
+
+ if (bmp_buffer == NULL)
+ {
+ fprintf(stderr, "DrawLineInDebugBitmap(): function called with NULL BMP buffer!\n");
+ return; // reliability check: cancel if bmp buffer unallocated
+ }
+
+ // translate the world coordinates in image pixel coordinates
+ x0 = (int)((v_from.x - minx) / scale);
+ y0 = (int)((v_from.y - miny) / scale);
+ x1 = (int)((v_to.x - minx) / scale);
+ y1 = (int)((v_to.y - miny) / scale);
+
+ dx = (x1 - x0) * 2;
+ dy = (y1 - y0) * 2;
+ if (dx < 0) { dx = -dx; stepx = -1; }
+ else stepx = 1;
+ if (dy < 0) { dy = -dy; stepy = -1; }
+ else stepy = 1;
+
+ offset = y0 * DEBUG_BMP_WIDTH + x0;
+ if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
+ fprintf(stderr, "DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
+ exit(1);
+ }
+
+ bmp_buffer[offset] = color; // draw the first point of the line
+
+ // is the line rather horizontal than vertical ? We need to know this to determine the step
+ // advance in the Bresenham grid, either we draw y = f(x), or x = f(y).
+ if (dx > dy)
+ {
+ // the line is rather horizontal, we can draw it safely for incremental values of x
+
+ fraction = 2 * dy - dx; // fraction of height in x0 pixel's 'square' where y0 should be
+
+ // while we've not reached the end of the segment...
+ while (x0 != x1)
+ {
+ // if y0 should rather be drawn on a different height than its previous height...
+ if (fraction >= 0)
+ {
+ y0 += stepy; // draw it one pixel aside, then (depending on line orientation)
+ fraction -= 2 * dx; // and reset its fraction (Bresenham, not sure I get the math)
+ }
+ x0 += stepx; // in either case, draw x0 one pixel aside its previous position
+ fraction += 2 * dy; // and update y0's fraction (not sure I get the math - but whatever)
+
+ // compute the offset in the BMP buffer corresponding to this point
+ offset = y0 * DEBUG_BMP_WIDTH + x0;
+ if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
+ fprintf(stderr, "DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
+ exit(1);
+ }
+
+ bmp_buffer[offset] = color; // set this point to have the specified color
+ }
+ }
+ else
+ {
+ // else the line is rather vertical, we NEED to draw it for incremental values of y (if we
+ // did it for incremental values of x instead, we would drop half the pixels).
+
+ fraction = 2 * dx - dy; // fraction of width in y0 pixel's 'square' where x0 should be
+
+ // while we've not reached the end of the segment...
+ while (y0 != y1)
+ {
+ // if x0 should rather be drawn on a different width than its previous width...
+ if (fraction >= 0)
+ {
+ x0 += stepx; // draw it one pixel aside, then (depending on line orientation)
+ fraction -= 2 * dy; // and reset its fraction (Bresenham, not sure I get the math)
+ }
+ y0 += stepy; // in either case, draw y0 one pixel aside its previous position
+ fraction += 2 * dx; // and update x0's fraction (not sure I get the math - but whatever)
+
+ // compute the offset in the BMP buffer corresponding to this point
+ offset = y0 * DEBUG_BMP_WIDTH + x0;
+ if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
+ fprintf(stderr, "DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n", offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
+ exit(1);
+ }
+ bmp_buffer[offset] = color; // set this point to have the specified color
+ }
+ }
+
+ return; // finished, segment has been printed into the BMP dot matrix
+}
+
+void WriteDebugBitmap(const char* mapname)
+{
+ // this function writes the debug bitmap image buffer in a .BMP file to disk. The format is
+ // 256 color and 2000 * 2000 pixels. The center of the world being roughly the center of the
+ // bitmap. The bitmap is stored in the file specified by 'filename' (which can be a relative
+ // path from the Half-Life base directory).
+ char filename[256];
+ FILE* fp;
+ int data_start, file_size;
+ unsigned long dummy;
+
+ if (bmp_buffer == NULL)
+ {
+ fprintf(stderr, "WriteDebugBitmap(): function called with NULL BMP buffer!\n");
+ return; // reliability check: cancel if bmp buffer unallocated
+ }
+
+ // open (or create) the .bmp file for writing in binary mode...
+ // Set Directory name
+ // strcpy (filename, "data/cstrike/maps/");
+ strcpy(filename, mapname);
+ strcat(filename, ".bmp"); // bitmap file
+ fp = fopen(filename, "wb");
+ if (fp == NULL)
+ {
+ fprintf(stderr, "RACC: WriteDebugBitmap(): unable to open BMP file!\n");
+ if (bmp_buffer)
+ free(bmp_buffer); // cannot open file, free DXF buffer
+ bmp_buffer = NULL;
+ return; // cancel if error creating file
+ }
+
+ // write the BMP header
+ fwrite("BM", 2, 1, fp); // write the BMP header tag
+ fseek(fp, sizeof(unsigned long), SEEK_CUR); // skip the file size field (will write it last)
+ fwrite("\0\0", sizeof(short), 1, fp); // dump zeros in the first reserved field (unused)
+ fwrite("\0\0", sizeof(short), 1, fp); // dump zeros in the second reserved field (unused)
+ fseek(fp, sizeof(unsigned long), SEEK_CUR); // skip the data start field (will write it last)
+
+ // write the info header
+ dummy = 40;
+ fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the info header size (does 40 bytes)
+ dummy = DEBUG_BMP_WIDTH;
+ fwrite(&dummy, sizeof(long), 1, fp); // write the image width (2000 px)
+ dummy = DEBUG_BMP_HEIGHT;
+ fwrite(&dummy, sizeof(long), 1, fp); // write the image height (2000 px)
+ dummy = 1;
+ fwrite(&dummy, sizeof(short), 1, fp); // write the # of planes (1)
+ dummy = 8;
+ fwrite(&dummy, sizeof(short), 1, fp); // write the bit count (8)
+ dummy = 0;
+ fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the compression id (no compression)
+ dummy = DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT;
+ fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the image size (2000 * 2000)
+ dummy = 0;
+ fwrite(&dummy, sizeof(long), 1, fp); // write the X pixels per meter (not specified)
+ fwrite(&dummy, sizeof(long), 1, fp); // write the Y pixels per meter (not specified)
+ dummy = 256;
+ fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the # of colors used (all)
+ fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the # of important colors (wtf ?)
+
+ // write the color palette (R, G, B, reserved byte)
+ fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp); // 0=BLACK
+ fputc(0xFF, fp); fputc(0xFF, fp); fputc(0xFF, fp); fputc(0x00, fp); // 1=WHITE
+ fputc(0x80, fp); fputc(0x80, fp); fputc(0x80, fp); fputc(0x00, fp); // 2=GREY
+ fputc(0xC0, fp); fputc(0xC0, fp); fputc(0xC0, fp); fputc(0x00, fp); // 3=SILVER
+ fputc(0x80, fp); fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp); // 4=DARK RED
+ fputc(0xFF, fp); fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp); // 5=RED
+ fputc(0x80, fp); fputc(0x80, fp); fputc(0x00, fp); fputc(0x00, fp); // 6=DARK YELLOW
+ fputc(0xFF, fp); fputc(0xFF, fp); fputc(0x00, fp); fputc(0x00, fp); // 7=YELLOW
+ fputc(0x00, fp); fputc(0x80, fp); fputc(0x00, fp); fputc(0x00, fp); // 8=DARK GREEN
+ fputc(0x00, fp); fputc(0xFF, fp); fputc(0x00, fp); fputc(0x00, fp); // 9=GREEN
+ fputc(0x00, fp); fputc(0x00, fp); fputc(0x80, fp); fputc(0x00, fp); // 10=DARK BLUE
+ fputc(0x00, fp); fputc(0x00, fp); fputc(0x80, fp); fputc(0x00, fp); // 11=BLUE
+ fputc(0x80, fp); fputc(0x00, fp); fputc(0x80, fp); fputc(0x00, fp); // 12=DARK PURPLE
+ fputc(0x80, fp); fputc(0x00, fp); fputc(0x80, fp); fputc(0x00, fp); // 13=PURPLE
+ fputc(0xFF, fp); fputc(0xFF, fp); fputc(0xFF, fp); fputc(0x00, fp); // 14=WHITE
+ fputc(0xEF, fp); fputc(0xEF, fp); fputc(0xEF, fp); fputc(0x00, fp); // 15=WHITE-GREY
+ fputc(0xDF, fp); fputc(0xDF, fp); fputc(0xDF, fp); fputc(0x00, fp); // 16=GREY
+ fputc(0xCF, fp); fputc(0xCF, fp); fputc(0xCF, fp); fputc(0x00, fp); // 17=DARKGREY
+ fputc(0xBF, fp); fputc(0xBF, fp); fputc(0xBF, fp); fputc(0x00, fp); // 18=DARKGREY
+ fputc(0xAF, fp); fputc(0xAF, fp); fputc(0xAF, fp); fputc(0x00, fp); // 19=DARKGREY
+
+ for (dummy = 20; dummy < 256; dummy++)
+ {
+ // fill out the rest of the palette with zeros
+ fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp); fputc(0x00, fp);
+ }
+
+ // write the actual image data
+ data_start = ftell(fp); // get the data start position (that's where we are now)
+ fwrite(bmp_buffer, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT, 1, fp); // write the image
+ file_size = ftell(fp); // get the file size now that the image is dumped
+
+ // now that we've dumped our data, we know the file size and the data start position
+
+ fseek(fp, 0, SEEK_SET); // rewind
+ fseek(fp, 2, SEEK_CUR); // skip the BMP header tag "BM"
+ fwrite(&file_size, sizeof(unsigned long), 1, fp); // write the file size at its location
+ fseek(fp, sizeof(short), SEEK_CUR); // skip the first reserved field
+ fseek(fp, sizeof(short), SEEK_CUR); // skip the second reserved field
+ fwrite(&data_start, sizeof(unsigned long), 1, fp); // write the data start at its location
+
+ fclose(fp); // finished, close the BMP file
+
+ if (bmp_buffer)
+ free(bmp_buffer); // and free the BMP buffer
+ bmp_buffer = NULL;
+
+ return; // and return
+}
+
+void FindMinMax(void)
+{
+ int i;
+
+ minx = miny = 9999.0;
+ maxx = maxy = -9999.0;
+ for (i = 0; i < iMaxUsedNodes; i++) {
+ if (Nodes[i].origin.x > maxx) maxx = Nodes[i].origin.x;
+ if (Nodes[i].origin.y > maxy) maxy = Nodes[i].origin.y;
+ if (Nodes[i].origin.x < minx) minx = Nodes[i].origin.x;
+ if (Nodes[i].origin.y < miny) miny = Nodes[i].origin.y;
+ }
+
+ // Add some margin
+ minx -= 32;
+ miny -= 32;
+ maxx += 32;
+ maxy += 32;
+ // first compute the X and Y divider scale, and take the greatest of both
+ scalex = (maxx - minx) / DEBUG_BMP_WIDTH;
+ scaley = (maxy - miny) / DEBUG_BMP_HEIGHT;
+ if (scalex > scaley)
+ scale = scalex + scalex / 100; // add a little offset (margin) for safety
+ else
+ scale = scaley + scaley / 100; // add a little offset (margin) for safety
+}
+
+// Mark meridians as slighly darker in alternance
+
+void MarkAxis(void)
+{
+ int x, y, x0, y0;
+
+ x0 = (int)((0 - minx) / scale);
+ y0 = (int)((0 - miny) / scale);
+
+ // Mark X axis by keeping X to 0 and varying Y
+ if ((minx < 0) && (0 < maxx))
+ for (y = 0; y < DEBUG_BMP_HEIGHT; y++)
+ bmp_buffer[y * DEBUG_BMP_WIDTH + x0] += 2;
+
+ // Mar
+ if ((miny < 0) && (0 < maxy))
+ for (x = 0; x < DEBUG_BMP_WIDTH; x++)
+ bmp_buffer[y0 * DEBUG_BMP_WIDTH + x] += 2;
+}
+
+void MarkMeredians(void)
+{
+ int x, y;
+ int Meredian;
+
+ // Mark some meredians
+ for (x = 0; x < DEBUG_BMP_WIDTH; x++) {
+ Meredian = abs(((float)x * scale + minx + 8192.0) / (float)SIZE_MEREDIAN);
+ if (Meredian & 0x01) {
+ for (y = 0; y < DEBUG_BMP_HEIGHT; y++)
+ bmp_buffer[y * DEBUG_BMP_WIDTH + x]++;
+ }
+ }
+
+ // Mark some meredians
+ for (y = 0; y < DEBUG_BMP_HEIGHT; y++) {
+ Meredian = abs(((float)y * scale + miny + 8192.0) / (float)SIZE_MEREDIAN);
+ if (Meredian & 0x01) {
+ for (x = 0; x < DEBUG_BMP_HEIGHT; x++)
+ bmp_buffer[y * DEBUG_BMP_WIDTH + x]++;
+ }
+ }
+}
+
+void PlotNodes(void)
+{
+ int i, j;
+
+ for (i = 0; i < iMaxUsedNodes; i++)
+ for (j = 0; (j < MAX_NEIGHBOURS) && (Nodes[i].iNeighbour[j] >= 0); j++)
+ DrawLineInDebugBitmap(Nodes[i].origin,
+ Nodes[Nodes[i].iNeighbour[j]].origin, 0);
+ for (i = 0; i < iMaxUsedNodes; i++)
+ DrawPoint(Nodes[i].origin, 5);
+}
+
+int main(int argc, char* argv[])
+{
+ printf("DrawNodes Version %s\nBy eric@vyncke.org\n", Version);
+ if (argc != 2) {
+ fprintf(stderr, "Usage is %s mapname\n", argv[0]);
+ exit;
+ }
+ load(argv[1]);
+ FindMinMax();
+ InitDebugBitmap();
+ MarkMeredians();
+ MarkAxis();
+ PlotNodes();
+ WriteDebugBitmap(argv[1]);
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/DumpNodes.c b/Bsp2Rbn/DumpNodes.c
index 5341fe3..1a35d78 100644
--- a/Bsp2Rbn/DumpNodes.c
+++ b/Bsp2Rbn/DumpNodes.c
@@ -2,7 +2,6 @@
evyncke@hec.be, June 2004
-
Based on routines from Stefan H.
*/
@@ -18,7 +17,7 @@ Based on routines from Stefan H.
#include "../bot.h"
#include "../NodeMachine.h"
-extern char * Version ;
+extern char* Version;
/* Copy from NodeMachine.cpp by Stefan Hendricks */
@@ -28,170 +27,168 @@ int Meredians[MAX_MEREDIANS][MAX_MEREDIANS]; // Meredian lookup search for No
int iMaxUsedNodes;
// Input: Vector, Output X and Y Meredians
-void VectorToMeredian (Vector vOrigin, int *iX, int *iY)
+void VectorToMeredian(Vector vOrigin, int* iX, int* iY)
{
- // Called for lookupt and for storing
- int iCoordX = abs (vOrigin.x + 8192.0); // map height (converts from - to +)
- int iCoordY = abs (vOrigin.y + 8192.0); // map width (converts from - to +)
+ // Called for lookupt and for storing
+ int iCoordX = abs(vOrigin.x + 8192.0); // map height (converts from - to +)
+ int iCoordY = abs(vOrigin.y + 8192.0); // map width (converts from - to +)
- // Meredian:
- iCoordX = abs (iCoordX / SIZE_MEREDIAN);
- iCoordY = abs (iCoordY / SIZE_MEREDIAN);
+ // Meredian:
+ iCoordX = abs(iCoordX / SIZE_MEREDIAN);
+ iCoordY = abs(iCoordY / SIZE_MEREDIAN);
- *iX = iCoordX;
- *iY = iCoordY;
+ *iX = iCoordX;
+ *iY = iCoordY;
}
-void load (char * mapname)
+void load(char* mapname)
{
- char filename[256];
- int i, j, n;
-
- strcpy (filename, mapname);
- strcat (filename, ".rbn"); // nodes file
-
- FILE *rbl;
- rbl = fopen (filename, "rb");
-
- if (rbl != NULL)
- {
- int iVersion ;
- fread (&iVersion, sizeof (int), 1, rbl);
-
- // Version 1.0
- if (iVersion == FILE_NODE_VER1)
- {
- for (i = 0; i < MAX_NODES; i++)
- {
- fread (&Nodes[i].origin, sizeof (Vector), 1, rbl);
- for (n = 0; n < MAX_NEIGHBOURS; n++)
- {
- fread (&Nodes[i].iNeighbour[n], sizeof (int), 1, rbl);
- }
-
- // save bit flags
- fread (&Nodes[i].iNodeBits, sizeof (int), 1, rbl);
-
- if (Nodes[i].origin != Vector (9999, 9999, 9999))
- iMaxUsedNodes = i;
- }
- }
- } else {
- fprintf(stderr,"Cannot open file %s\n",filename) ;
- exit ;
- }
- printf("%d nodes loaded out of %d.\n",iMaxUsedNodes,MAX_NODES) ;
- fclose(rbl) ;
-
- // Zero the Meredians table
- for (i=0;i -1 && iY > -1)
- Meredians[iX][iY] ++ ;
- }
+ char filename[256];
+ int i, j, n;
+
+ strcpy(filename, mapname);
+ strcat(filename, ".rbn"); // nodes file
+ FILE* rbl;
+ rbl = fopen(filename, "rb");
+ if (rbl != NULL)
+ {
+ int iVersion;
+ fread(&iVersion, sizeof(int), 1, rbl);
+
+ // Version 1.0
+ if (iVersion == FILE_NODE_VER1)
+ {
+ for (i = 0; i < MAX_NODES; i++)
+ {
+ fread(&Nodes[i].origin, sizeof(Vector), 1, rbl);
+ for (n = 0; n < MAX_NEIGHBOURS; n++)
+ {
+ fread(&Nodes[i].iNeighbour[n], sizeof(int), 1, rbl);
+ }
+
+ // save bit flags
+ fread(&Nodes[i].iNodeBits, sizeof(int), 1, rbl);
+
+ if (Nodes[i].origin != Vector(9999, 9999, 9999))
+ iMaxUsedNodes = i;
+ }
+ }
+ }
+ else {
+ fprintf(stderr, "Cannot open file %s\n", filename);
+ exit;
+ }
+ printf("%d nodes loaded out of %d.\n", iMaxUsedNodes, MAX_NODES);
+ fclose(rbl);
+
+ // Zero the Meredians table
+ for (i = 0;i < MAX_MEREDIANS;i++)
+ for (j = 0;j < MAX_MEREDIANS;j++)
+ Meredians[i][j] = 0;
+
+ // Add nodes to meredians
+ for (i = 0; i < MAX_NODES; i++)
+ if (Nodes[i].origin != Vector(9999, 9999, 9999))
+ {
+ int iX, iY;
+ VectorToMeredian(Nodes[i].origin, &iX, &iY);
+ if (iX > -1 && iY > -1)
+ Meredians[iX][iY] ++;
+ }
}
-void PrintNodesPair(int iMe, int iNext, Vector Me, Vector Next)
+void PrintNodesPair(int iMe, int iNext, Vector Me, Vector Next)
{
- int MeX, MeY, NextX, NextY ; // Meredians
-
- printf(" dist(%d,%d)=%.0f",iMe,iNext,(Next-Me).Length()) ;
- VectorToMeredian(Me,&MeX,&MeY) ;
- VectorToMeredian(Next,&NextX,&NextY) ;
- if (abs(Me.z-Next.z) > 5) printf(", altitude diff=%d",abs(Me.z-Next.z)) ;
- if ((MeX != NextX) && (MeY != NextY))
- printf(", Both meredians do not match!") ;
- else if ((MeX != NextX) || (MeY != NextY))
- printf(", One Meredian does not match!") ;
- printf("\n") ;
+ int MeX, MeY, NextX, NextY; // Meredians
+
+ printf(" dist(%d,%d)=%.0f", iMe, iNext, (Next - Me).Length());
+ VectorToMeredian(Me, &MeX, &MeY);
+ VectorToMeredian(Next, &NextX, &NextY);
+ if (abs(Me.z - Next.z) > 5) printf(", altitude diff=%d", abs(Me.z - Next.z));
+ if ((MeX != NextX) && (MeY != NextY))
+ printf(", Both meredians do not match!");
+ else if ((MeX != NextX) || (MeY != NextY))
+ printf(", One Meredian does not match!");
+ printf("\n");
}
// Analyze the RBN file which has just been read...
void AnalyseNeighbours(void)
{
- int MeX, MeY, NextX, NextY ; // Meredians
- int Count,i,j ;
- int Histogram[MAX_NEIGHBOURS+1] ; // Will count the frequency of nodes having 0... N neighbours
- Vector Me, Next ;
- float Distance ;
-
- for (i=0;i= 0);j++)
- Count ++ ;
- Histogram[j]++ ;
+ for (j = 0; (j < MAX_NEIGHBOURS) && (Nodes[i].iNeighbour[j] >= 0);j++)
+ Count++;
+ Histogram[j]++;
}
- printf("There are %d neighbours (i.e. %.1f neighbour(s) per node out of %d)\n",Count,(float) Count / (float) iMaxUsedNodes,MAX_NEIGHBOURS) ;
- printf("Neighbours distribution\n") ;
- for (j=0;j NODE_ZONE*2) continue ;
- PrintNodesPair(i, i-1, Me, Next) ;
+ for (i = 1; i < iMaxUsedNodes; i++)
+ if (Nodes[i].iNeighbour[0] < 0) {
+ Me = Nodes[i].origin;
+ Next = Nodes[i - 1].origin;
+ Distance = (Next - Me).Length();
+ if (Distance > NODE_ZONE * 2) continue;
+ PrintNodesPair(i, i - 1, Me, Next);
}
- printf("Isolated nodes that are close to the next one (HIGHLY suspicious):\n") ;
- for (i=0; i < iMaxUsedNodes-1; i++)
- if (Nodes[i].iNeighbour[0]< 0) {
- Me=Nodes[i].origin ;
- Next=Nodes[i+1].origin ;
- Distance=(Next-Me).Length() ;
- if (Distance > NODE_ZONE*2) continue ;
- PrintNodesPair(i, i+1, Me, Next) ;
+ printf("Isolated nodes that are close to the next one (HIGHLY suspicious):\n");
+ for (i = 0; i < iMaxUsedNodes - 1; i++)
+ if (Nodes[i].iNeighbour[0] < 0) {
+ Me = Nodes[i].origin;
+ Next = Nodes[i + 1].origin;
+ Distance = (Next - Me).Length();
+ if (Distance > NODE_ZONE * 2) continue;
+ PrintNodesPair(i, i + 1, Me, Next);
}
}
}
void AnalyseMeredians(void)
{
- int i, j ;
+ int i, j;
- for (i=0;i= MAX_NODES_IN_MEREDIANS) printf("Too many nodes on meredians(%d,%d): %d (max %d)\n",
- i, j, Meredians[i][j], MAX_NODES_IN_MEREDIANS) ;
+ i, j, Meredians[i][j], MAX_NODES_IN_MEREDIANS);
}
-int main (int argc, char * argv[])
+int main(int argc, char* argv[])
{
- if (argc != 2) {
- fprintf(stderr,"Usage is %s mapname\n",argv[0]) ;
- exit ;
+ if (argc != 2) {
+ fprintf(stderr, "Usage is %s mapname\n", argv[0]);
+ exit;
}
- printf("DumpNodes Version %s\nBy eric@vyncke.org\n",Version) ;
- load(argv[1]) ;
- AnalyseNeighbours() ;
- AnalyseMeredians() ;
-}
-
+ printf("DumpNodes Version %s\nBy eric@vyncke.org\n", Version);
+ load(argv[1]);
+ AnalyseNeighbours();
+ AnalyseMeredians();
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/Makefile b/Bsp2Rbn/Makefile
index 4037829..85df3d4 100644
--- a/Bsp2Rbn/Makefile
+++ b/Bsp2Rbn/Makefile
@@ -1,14 +1,14 @@
# CPP must be g++ on Linux
CPP = g++
-ARCHFLAG = i586
+ARCHFLAG = i686
-METAMOD_SRCDIR = ../../metamod-1.17/metamod
+METAMOD_SRCDIR = ../../metamod-p/metamod
-HLSDK_BASEDIR = ../../HLSDK
+HLSDK_BASEDIR = ../../hlsdk-2.3-p4
BASEFLAGS = -g -Wall
-CPPFLAGS = ${BASEFLAGS} -march=${ARCHFLAG} -O2 -w -I"${METAMOD_SRCDIR}" -I"${HLSDK_BASEDIR}/multiplayer/common" -I"${HLSDK_BASEDIR}/multiplayer/dlls" -I"${HLSDK_BASEDIR}/multiplayer/engine" -I"${HLSDK_BASEDIR}/multiplayer/pm_shared"
+CPPFLAGS = ${BASEFLAGS} -march=${ARCHFLAG} -O2 -w -I"${METAMOD_SRCDIR}" -I"${HLSDK_BASEDIR}/multiplayer/common" -I"${HLSDK_BASEDIR}/multiplayer/dlls" -I"${HLSDK_BASEDIR}/multiplayer/engine" -I"${HLSDK_BASEDIR}/multiplayer/pm_shared" -I"${HLSDK_BASEDIR}/multiplayer/public"
all: Bsp2Rbn DumpNodes DrawNodes
@@ -34,4 +34,4 @@ clean:
%.o: %.c
${CPP} ${CPPFLAGS} -c $< -o $@
-
+
diff --git a/Bsp2Rbn/bspfile.cpp b/Bsp2Rbn/bspfile.cpp
index 046b1cd..c02cbe5 100644
--- a/Bsp2Rbn/bspfile.cpp
+++ b/Bsp2Rbn/bspfile.cpp
@@ -2,8 +2,8 @@
*
* Copyright (c) 1998, Valve LLC. All rights reserved.
*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
****/
@@ -27,70 +27,69 @@
// Make all of these dynamice for BSP_tool...
int nummodels = 0;
-dmodel_t *dmodels = NULL;
+dmodel_t* dmodels = NULL;
int visdatasize = 0;
-byte *dvisdata = NULL;
+byte* dvisdata = NULL;
int lightdatasize = 0;
-byte *dlightdata = NULL;
+byte* dlightdata = NULL;
int texdatasize = 0;
-byte *dtexdata = NULL;
+byte* dtexdata = NULL;
int entdatasize = 0;
-char *dentdata = NULL;
+char* dentdata = NULL;
int numleafs = 0;
-dleaf_t *dleafs = NULL;
+dleaf_t* dleafs = NULL;
int numplanes = 0;
-dplane_t *dplanes = NULL;
+dplane_t* dplanes = NULL;
int numvertexes = 0;
-dvertex_t *dvertexes = NULL;
+dvertex_t* dvertexes = NULL;
int numnodes = 0;
-dnode_t *dnodes = NULL;
+dnode_t* dnodes = NULL;
int numtexinfo = 0;
-texinfo_t *texinfo = NULL;
+texinfo_t* texinfo = NULL;
int numfaces = 0;
-dface_t *dfaces = NULL;
+dface_t* dfaces = NULL;
int numclipnodes = 0;
-dclipnode_t *dclipnodes = NULL;
+dclipnode_t* dclipnodes = NULL;
int numedges = 0;
-dedge_t *dedges = NULL;
+dedge_t* dedges = NULL;
int nummarksurfaces = 0;
-unsigned short *dmarksurfaces = NULL;
+unsigned short* dmarksurfaces = NULL;
int numsurfedges = 0;
-int *dsurfedges = NULL;
+int* dsurfedges = NULL;
int num_entities = 0;
entity_t entities[MAX_MAP_ENTITIES];
-
#ifdef __linux__
-unsigned _rotl ( unsigned val, int shift)
+unsigned _rotl(unsigned val, int shift)
{
- register unsigned hibit; /* non-zero means hi bit set */
- register unsigned num = val; /* number to rotate */
-
- shift &= 0x1f; /* modulo 32 -- this will also make
- negative shifts work */
- while (shift--) {
- hibit = num & 0x80000000; /* get high bit */
- num <<= 1; /* shift left one bit */
- if (hibit)
- num |= 1; /* set lo bit if hi bit was set */
- }
-
- return num;
+ register unsigned hibit; /* non-zero means hi bit set */
+ register unsigned num = val; /* number to rotate */
+
+ shift &= 0x1f; /* modulo 32 -- this will also make
+ negative shifts work */
+ while (shift--) {
+ hibit = num & 0x80000000; /* get high bit */
+ num <<= 1; /* shift left one bit */
+ if (hibit)
+ num |= 1; /* set lo bit if hi bit was set */
+ }
+
+ return num;
}
#endif
@@ -100,17 +99,17 @@ FastChecksum
===============
*/
-int FastChecksum(char *buffer, int bytes)
+int FastChecksum(char* buffer, int bytes)
{
- int checksum = 0;
+ int checksum = 0;
- while( bytes-- )
- {
- checksum = _rotl(checksum, 4) ^ *(char *)buffer;
- buffer++;
- }
+ while (bytes--)
+ {
+ checksum = _rotl(checksum, 4) ^ *(char*)buffer;
+ buffer++;
+ }
- return checksum;
+ return checksum;
}
/*
@@ -118,66 +117,65 @@ int FastChecksum(char *buffer, int bytes)
CompressVis
===============
*/
-int CompressVis (byte *vis, byte *dest)
+int CompressVis(byte* vis, byte* dest)
{
- int j;
- int rep;
- int visrow;
- byte *dest_p;
-
- dest_p = dest;
- visrow = (numleafs + 7)>>3;
-
- for (j=0 ; j> 3;
+
+ for (j = 0; j < visrow; j++)
+ {
+ *dest_p++ = vis[j];
+ if (vis[j])
+ continue;
+
+ rep = 1;
+ for (j++; j < visrow; j++)
+ if (vis[j] || rep == 255)
+ break;
+ else
+ rep++;
+ *dest_p++ = rep;
+ j--;
+ }
+
+ return dest_p - dest;
}
-
/*
===================
DecompressVis
===================
*/
-void DecompressVis (byte *in, byte *decompressed)
+void DecompressVis(byte* in, byte* decompressed)
{
- int c;
- byte *out;
- int row;
-
- row = (numleafs+7)>>3;
- out = decompressed;
-
- do
- {
- if (*in)
- {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- in += 2;
- while (c)
- {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
+ int c;
+ byte* out;
+ int row;
+
+ row = (numleafs + 7) >> 3;
+ out = decompressed;
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ in += 2;
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
}
//=============================================================================
@@ -189,186 +187,184 @@ SwapBSPFile
Byte swaps all data in a bsp file.
=============
*/
-void SwapBSPFile (qboolean todisk)
+void SwapBSPFile(qboolean todisk)
{
- int i, j, c;
- dmodel_t *d;
- dmiptexlump_t *mtl;
-
-
-// models
- for (i=0 ; iheadnode[j] = LittleLong (d->headnode[j]);
-
- d->visleafs = LittleLong (d->visleafs);
- d->firstface = LittleLong (d->firstface);
- d->numfaces = LittleLong (d->numfaces);
-
- for (j=0 ; j<3 ; j++)
- {
- d->mins[j] = LittleFloat(d->mins[j]);
- d->maxs[j] = LittleFloat(d->maxs[j]);
- d->origin[j] = LittleFloat(d->origin[j]);
- }
- }
-
-//
-// vertexes
-//
- for (i=0 ; inummiptex;
- else
- c = LittleLong(mtl->nummiptex);
- mtl->nummiptex = LittleLong (mtl->nummiptex);
- for (i=0 ; idataofs[i] = LittleLong(mtl->dataofs[i]);
- }
-
-//
-// marksurfaces
-//
- for (i=0 ; iheadnode[j] = LittleLong(d->headnode[j]);
+
+ d->visleafs = LittleLong(d->visleafs);
+ d->firstface = LittleLong(d->firstface);
+ d->numfaces = LittleLong(d->numfaces);
+
+ for (j = 0; j < 3; j++)
+ {
+ d->mins[j] = LittleFloat(d->mins[j]);
+ d->maxs[j] = LittleFloat(d->maxs[j]);
+ d->origin[j] = LittleFloat(d->origin[j]);
+ }
+ }
+
+ //
+ // vertexes
+ //
+ for (i = 0; i < numvertexes; i++)
+ {
+ for (j = 0; j < 3; j++)
+ dvertexes[i].point[j] = LittleFloat(dvertexes[i].point[j]);
+ }
+
+ //
+ // planes
+ //
+ for (i = 0; i < numplanes; i++)
+ {
+ for (j = 0; j < 3; j++)
+ dplanes[i].normal[j] = LittleFloat(dplanes[i].normal[j]);
+ dplanes[i].dist = LittleFloat(dplanes[i].dist);
+ dplanes[i].type = LittleLong(dplanes[i].type);
+ }
+
+ //
+ // texinfos
+ //
+ for (i = 0; i < numtexinfo; i++)
+ {
+ for (j = 0; j < 8; j++)
+ texinfo[i].vecs[0][j] = LittleFloat(texinfo[i].vecs[0][j]);
+ texinfo[i].miptex = LittleLong(texinfo[i].miptex);
+ texinfo[i].flags = LittleLong(texinfo[i].flags);
+ }
+
+ //
+ // faces
+ //
+ for (i = 0; i < numfaces; i++)
+ {
+ dfaces[i].texinfo = LittleShort(dfaces[i].texinfo);
+ dfaces[i].planenum = LittleShort(dfaces[i].planenum);
+ dfaces[i].side = LittleShort(dfaces[i].side);
+ dfaces[i].lightofs = LittleLong(dfaces[i].lightofs);
+ dfaces[i].firstedge = LittleLong(dfaces[i].firstedge);
+ dfaces[i].numedges = LittleShort(dfaces[i].numedges);
+ }
+
+ //
+ // nodes
+ //
+ for (i = 0; i < numnodes; i++)
+ {
+ dnodes[i].planenum = LittleLong(dnodes[i].planenum);
+ for (j = 0; j < 3; j++)
+ {
+ dnodes[i].mins[j] = LittleShort(dnodes[i].mins[j]);
+ dnodes[i].maxs[j] = LittleShort(dnodes[i].maxs[j]);
+ }
+ dnodes[i].children[0] = LittleShort(dnodes[i].children[0]);
+ dnodes[i].children[1] = LittleShort(dnodes[i].children[1]);
+ dnodes[i].firstface = LittleShort(dnodes[i].firstface);
+ dnodes[i].numfaces = LittleShort(dnodes[i].numfaces);
+ }
+
+ //
+ // leafs
+ //
+ for (i = 0; i < numleafs; i++)
+ {
+ dleafs[i].contents = LittleLong(dleafs[i].contents);
+ for (j = 0; j < 3; j++)
+ {
+ dleafs[i].mins[j] = LittleShort(dleafs[i].mins[j]);
+ dleafs[i].maxs[j] = LittleShort(dleafs[i].maxs[j]);
+ }
+
+ dleafs[i].firstmarksurface = LittleShort(dleafs[i].firstmarksurface);
+ dleafs[i].nummarksurfaces = LittleShort(dleafs[i].nummarksurfaces);
+ dleafs[i].visofs = LittleLong(dleafs[i].visofs);
+ }
+
+ //
+ // clipnodes
+ //
+ for (i = 0; i < numclipnodes; i++)
+ {
+ dclipnodes[i].planenum = LittleLong(dclipnodes[i].planenum);
+ dclipnodes[i].children[0] = LittleShort(dclipnodes[i].children[0]);
+ dclipnodes[i].children[1] = LittleShort(dclipnodes[i].children[1]);
+ }
+
+ //
+ // miptex
+ //
+ if (texdatasize)
+ {
+ mtl = (dmiptexlump_t*)dtexdata;
+ if (todisk)
+ c = mtl->nummiptex;
+ else
+ c = LittleLong(mtl->nummiptex);
+ mtl->nummiptex = LittleLong(mtl->nummiptex);
+ for (i = 0; i < c; i++)
+ mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
+ }
+
+ //
+ // marksurfaces
+ //
+ for (i = 0; i < nummarksurfaces; i++)
+ dmarksurfaces[i] = LittleShort(dmarksurfaces[i]);
+
+ //
+ // surfedges
+ //
+ for (i = 0; i < numsurfedges; i++)
+ dsurfedges[i] = LittleLong(dsurfedges[i]);
+
+ //
+ // edges
+ //
+ for (i = 0; i < numedges; i++)
+ {
+ dedges[i].v[0] = LittleShort(dedges[i].v[0]);
+ dedges[i].v[1] = LittleShort(dedges[i].v[1]);
+ }
}
+dheader_t* header;
-dheader_t *header;
-
-int CopyLump (int lump, void **dest, int size)
+int CopyLump(int lump, void** dest, int size)
{
- int length, ofs;
- int num;
+ int length, ofs;
+ int num;
- length = header->lumps[lump].filelen;
- ofs = header->lumps[lump].fileofs;
+ length = header->lumps[lump].filelen;
+ ofs = header->lumps[lump].fileofs;
- if (length % size)
- Error ("LoadBSPFile: odd lump size");
+ if (length % size)
+ Error("LoadBSPFile: odd lump size");
- num = length / size;
+ num = length / size;
- if (*dest == NULL)
- {
- // allocate memory for this lump...
- *dest = malloc(num * size);
+ if (*dest == NULL)
+ {
+ // allocate memory for this lump...
+ *dest = malloc(num * size);
- if (*dest == NULL)
- Error("Error allocating memory for BSP file lump!\n");
- }
+ if (*dest == NULL)
+ Error("Error allocating memory for BSP file lump!\n");
+ }
- memcpy (*dest, (byte *)header + ofs, length);
+ memcpy(*dest, (byte*)header + ofs, length);
- return num;
+ return num;
}
/*
@@ -376,82 +372,81 @@ int CopyLump (int lump, void **dest, int size)
LoadBSPFile
=============
*/
-void LoadBSPFile (char *filename)
+void LoadBSPFile(char* filename)
{
- int i;
-
-//
-// load the file header
-//
- if (LoadFile (filename, (void **)&header) < sizeof(dheader_t))
- Error ("File %s is too short",filename) ;
-
- if (header == NULL)
- Error ("Cannot read file %s",filename) ;
-
-// swap the header
- for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
-
- if (header->version != BSPVERSION)
- Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
-
- nummodels = CopyLump (LUMP_MODELS, (void **)&dmodels, sizeof(dmodel_t));
- numvertexes = CopyLump (LUMP_VERTEXES, (void **)&dvertexes, sizeof(dvertex_t));
- numplanes = CopyLump (LUMP_PLANES, (void **)&dplanes, sizeof(dplane_t));
- numleafs = CopyLump (LUMP_LEAFS, (void **)&dleafs, sizeof(dleaf_t));
- numnodes = CopyLump (LUMP_NODES, (void **)&dnodes, sizeof(dnode_t));
- numtexinfo = CopyLump (LUMP_TEXINFO, (void **)&texinfo, sizeof(texinfo_t));
- numclipnodes = CopyLump (LUMP_CLIPNODES, (void **)&dclipnodes, sizeof(dclipnode_t));
- numfaces = CopyLump (LUMP_FACES, (void **)&dfaces, sizeof(dface_t));
- nummarksurfaces = CopyLump (LUMP_MARKSURFACES, (void **)&dmarksurfaces, sizeof(dmarksurfaces[0]));
- numsurfedges = CopyLump (LUMP_SURFEDGES, (void **)&dsurfedges, sizeof(dsurfedges[0]));
- numedges = CopyLump (LUMP_EDGES, (void **)&dedges, sizeof(dedge_t));
-
- texdatasize = CopyLump (LUMP_TEXTURES, (void **)&dtexdata, 1);
- visdatasize = CopyLump (LUMP_VISIBILITY, (void **)&dvisdata, 1);
- lightdatasize = CopyLump (LUMP_LIGHTING, (void **)&dlightdata, 1);
- entdatasize = CopyLump (LUMP_ENTITIES, (void **)&dentdata, 1);
-
- free (header); // everything has been copied out
-
-//
-// swap everything
-//
- SwapBSPFile (false);
-
-// dmodels_checksum = FastChecksum( (char *)dmodels, nummodels*sizeof(dmodels[0]) );
-// dvertexes_checksum = FastChecksum( (char *)dvertexes, numvertexes*sizeof(dvertexes[0]) );
-// dplanes_checksum = FastChecksum( (char *)dplanes, numplanes*sizeof(dplanes[0]) );
-// dleafs_checksum = FastChecksum( (char *)dleafs, numleafs*sizeof(dleafs[0]) );
-// dnodes_checksum = FastChecksum( (char *)dnodes, numnodes*sizeof(dnodes[0]) );
-// texinfo_checksum = FastChecksum( (char *)texinfo, numtexinfo*sizeof(texinfo[0]) );
-// dclipnodes_checksum = FastChecksum( (char *)dclipnodes, numclipnodes*sizeof(dclipnodes[0]) );
-// dfaces_checksum = FastChecksum( (char *)dfaces, numfaces*sizeof(dfaces[0]) );
-// dmarksurfaces_checksum = FastChecksum( (char *)dmarksurfaces, nummarksurfaces*sizeof(dmarksurfaces[0]) );
-// dsurfedges_checksum = FastChecksum( (char *)dsurfedges, numsurfedges*sizeof(dsurfedges[0]) );
-// dedges_checksum = FastChecksum( (char *)dedges, numedges*sizeof(dedges[0]) );
-// dtexdata_checksum = FastChecksum( (char *)dtexdata, numedges*sizeof(dtexdata[0]) );
-// dvisdata_checksum = FastChecksum( (char *)dvisdata, visdatasize*sizeof(dvisdata[0]) );
-// dlightdata_checksum = FastChecksum( (char *)dlightdata, lightdatasize*sizeof(dlightdata[0]) );
-// dentdata_checksum = FastChecksum( (char *)dentdata, entdatasize*sizeof(dentdata[0]) );
-
+ int i;
+
+ //
+ // load the file header
+ //
+ if (LoadFile(filename, (void**)&header) < sizeof(dheader_t))
+ Error("File %s is too short", filename);
+
+ if (header == NULL)
+ Error("Cannot read file %s", filename);
+
+ // swap the header
+ for (i = 0; i < sizeof(dheader_t) / 4; i++)
+ ((int*)header)[i] = LittleLong(((int*)header)[i]);
+
+ if (header->version != BSPVERSION)
+ Error("%s is version %i, not %i", filename, header->version, BSPVERSION);
+
+ nummodels = CopyLump(LUMP_MODELS, (void**)&dmodels, sizeof(dmodel_t));
+ numvertexes = CopyLump(LUMP_VERTEXES, (void**)&dvertexes, sizeof(dvertex_t));
+ numplanes = CopyLump(LUMP_PLANES, (void**)&dplanes, sizeof(dplane_t));
+ numleafs = CopyLump(LUMP_LEAFS, (void**)&dleafs, sizeof(dleaf_t));
+ numnodes = CopyLump(LUMP_NODES, (void**)&dnodes, sizeof(dnode_t));
+ numtexinfo = CopyLump(LUMP_TEXINFO, (void**)&texinfo, sizeof(texinfo_t));
+ numclipnodes = CopyLump(LUMP_CLIPNODES, (void**)&dclipnodes, sizeof(dclipnode_t));
+ numfaces = CopyLump(LUMP_FACES, (void**)&dfaces, sizeof(dface_t));
+ nummarksurfaces = CopyLump(LUMP_MARKSURFACES, (void**)&dmarksurfaces, sizeof(dmarksurfaces[0]));
+ numsurfedges = CopyLump(LUMP_SURFEDGES, (void**)&dsurfedges, sizeof(dsurfedges[0]));
+ numedges = CopyLump(LUMP_EDGES, (void**)&dedges, sizeof(dedge_t));
+
+ texdatasize = CopyLump(LUMP_TEXTURES, (void**)&dtexdata, 1);
+ visdatasize = CopyLump(LUMP_VISIBILITY, (void**)&dvisdata, 1);
+ lightdatasize = CopyLump(LUMP_LIGHTING, (void**)&dlightdata, 1);
+ entdatasize = CopyLump(LUMP_ENTITIES, (void**)&dentdata, 1);
+
+ free(header); // everything has been copied out
+
+ //
+ // swap everything
+ //
+ SwapBSPFile(false);
+
+ // dmodels_checksum = FastChecksum( (char *)dmodels, nummodels*sizeof(dmodels[0]) );
+ // dvertexes_checksum = FastChecksum( (char *)dvertexes, numvertexes*sizeof(dvertexes[0]) );
+ // dplanes_checksum = FastChecksum( (char *)dplanes, numplanes*sizeof(dplanes[0]) );
+ // dleafs_checksum = FastChecksum( (char *)dleafs, numleafs*sizeof(dleafs[0]) );
+ // dnodes_checksum = FastChecksum( (char *)dnodes, numnodes*sizeof(dnodes[0]) );
+ // texinfo_checksum = FastChecksum( (char *)texinfo, numtexinfo*sizeof(texinfo[0]) );
+ // dclipnodes_checksum = FastChecksum( (char *)dclipnodes, numclipnodes*sizeof(dclipnodes[0]) );
+ // dfaces_checksum = FastChecksum( (char *)dfaces, numfaces*sizeof(dfaces[0]) );
+ // dmarksurfaces_checksum = FastChecksum( (char *)dmarksurfaces, nummarksurfaces*sizeof(dmarksurfaces[0]) );
+ // dsurfedges_checksum = FastChecksum( (char *)dsurfedges, numsurfedges*sizeof(dsurfedges[0]) );
+ // dedges_checksum = FastChecksum( (char *)dedges, numedges*sizeof(dedges[0]) );
+ // dtexdata_checksum = FastChecksum( (char *)dtexdata, numedges*sizeof(dtexdata[0]) );
+ // dvisdata_checksum = FastChecksum( (char *)dvisdata, visdatasize*sizeof(dvisdata[0]) );
+ // dlightdata_checksum = FastChecksum( (char *)dlightdata, lightdatasize*sizeof(dlightdata[0]) );
+ // dentdata_checksum = FastChecksum( (char *)dentdata, entdatasize*sizeof(dentdata[0]) );
}
//============================================================================
-FILE *wadfile;
+FILE* wadfile;
dheader_t outheader;
-void AddLump (int lumpnum, void *data, int len)
+void AddLump(int lumpnum, void* data, int len)
{
- lump_t *lump;
+ lump_t* lump;
- lump = &header->lumps[lumpnum];
+ lump = &header->lumps[lumpnum];
- lump->fileofs = LittleLong( ftell(wadfile) );
- lump->filelen = LittleLong(len);
- SafeWrite (wadfile, data, (len+3)&~3);
+ lump->fileofs = LittleLong(ftell(wadfile));
+ lump->filelen = LittleLong(len);
+ SafeWrite(wadfile, data, (len + 3) & ~3);
}
/*
@@ -461,38 +456,38 @@ WriteBSPFile
Swaps the bsp file in place, so it should not be referenced again
=============
*/
-void WriteBSPFile (char *filename)
-{
- header = &outheader;
- memset (header, 0, sizeof(dheader_t));
-
- SwapBSPFile (true);
-
- header->version = LittleLong (BSPVERSION);
-
- wadfile = SafeOpenWrite (filename);
- SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later
-
- AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));
- AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));
- AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));
- AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));
- AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));
- AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));
- AddLump (LUMP_CLIPNODES, dclipnodes, numclipnodes*sizeof(dclipnode_t));
- AddLump (LUMP_MARKSURFACES, dmarksurfaces, nummarksurfaces*sizeof(dmarksurfaces[0]));
- AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));
- AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));
- AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));
-
- AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);
- AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);
- AddLump (LUMP_ENTITIES, dentdata, entdatasize);
- AddLump (LUMP_TEXTURES, dtexdata, texdatasize);
-
- fseek (wadfile, 0, SEEK_SET);
- SafeWrite (wadfile, header, sizeof(dheader_t));
- fclose (wadfile);
+void WriteBSPFile(char* filename)
+{
+ header = &outheader;
+ memset(header, 0, sizeof(dheader_t));
+
+ SwapBSPFile(true);
+
+ header->version = LittleLong(BSPVERSION);
+
+ wadfile = SafeOpenWrite(filename);
+ SafeWrite(wadfile, header, sizeof(dheader_t)); // overwritten later
+
+ AddLump(LUMP_PLANES, dplanes, numplanes * sizeof(dplane_t));
+ AddLump(LUMP_LEAFS, dleafs, numleafs * sizeof(dleaf_t));
+ AddLump(LUMP_VERTEXES, dvertexes, numvertexes * sizeof(dvertex_t));
+ AddLump(LUMP_NODES, dnodes, numnodes * sizeof(dnode_t));
+ AddLump(LUMP_TEXINFO, texinfo, numtexinfo * sizeof(texinfo_t));
+ AddLump(LUMP_FACES, dfaces, numfaces * sizeof(dface_t));
+ AddLump(LUMP_CLIPNODES, dclipnodes, numclipnodes * sizeof(dclipnode_t));
+ AddLump(LUMP_MARKSURFACES, dmarksurfaces, nummarksurfaces * sizeof(dmarksurfaces[0]));
+ AddLump(LUMP_SURFEDGES, dsurfedges, numsurfedges * sizeof(dsurfedges[0]));
+ AddLump(LUMP_EDGES, dedges, numedges * sizeof(dedge_t));
+ AddLump(LUMP_MODELS, dmodels, nummodels * sizeof(dmodel_t));
+
+ AddLump(LUMP_LIGHTING, dlightdata, lightdatasize);
+ AddLump(LUMP_VISIBILITY, dvisdata, visdatasize);
+ AddLump(LUMP_ENTITIES, dentdata, entdatasize);
+ AddLump(LUMP_TEXTURES, dtexdata, texdatasize);
+
+ fseek(wadfile, 0, SEEK_SET);
+ SafeWrite(wadfile, header, sizeof(dheader_t));
+ fclose(wadfile);
}
//============================================================================
@@ -500,37 +495,37 @@ void WriteBSPFile (char *filename)
//#define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
//#define ENTRYSIZE(a) (sizeof(*(a)))
-int ArrayUsage( char *szItem, int items, int maxitems, int itemsize )
+int ArrayUsage(char* szItem, int items, int maxitems, int itemsize)
{
- float percentage = maxitems ? items * (float)100.0 / maxitems : (float)0.0;
-
- printf("%-12s %7i/%-7i %7i/%-7i (%4.1f%%)",
- szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
- if ( percentage > 80.0 )
- printf( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- printf( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- printf( "SIZE OVERFLOW!!!\n" );
- else
- printf( "\n" );
- return items * itemsize;
+ float percentage = maxitems ? items * (float)100.0 / maxitems : (float)0.0;
+
+ printf("%-12s %7i/%-7i %7i/%-7i (%4.1f%%)",
+ szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage);
+ if (percentage > 80.0)
+ printf("VERY FULL!\n");
+ else if (percentage > 95.0)
+ printf("SIZE DANGER!\n");
+ else if (percentage > 99.9)
+ printf("SIZE OVERFLOW!!!\n");
+ else
+ printf("\n");
+ return items * itemsize;
}
-int GlobUsage( char *szItem, int itemstorage, int maxstorage )
+int GlobUsage(char* szItem, int itemstorage, int maxstorage)
{
- float percentage = maxstorage ? itemstorage * (float)100.0 / maxstorage : (float)0.0;
- printf("%-12s [variable] %7i/%-7i (%4.1f%%)",
- szItem, itemstorage, maxstorage, percentage );
- if ( percentage > 80.0 )
- printf( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- printf( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- printf( "SIZE OVERFLOW!!!\n" );
- else
- printf( "\n" );
- return itemstorage;
+ float percentage = maxstorage ? itemstorage * (float)100.0 / maxstorage : (float)0.0;
+ printf("%-12s [variable] %7i/%-7i (%4.1f%%)",
+ szItem, itemstorage, maxstorage, percentage);
+ if (percentage > 80.0)
+ printf("VERY FULL!\n");
+ else if (percentage > 95.0)
+ printf("SIZE DANGER!\n");
+ else if (percentage > 99.9)
+ printf("SIZE OVERFLOW!!!\n");
+ else
+ printf("\n");
+ return itemstorage;
}
/*
@@ -540,73 +535,71 @@ PrintBSPFileSizes
Dumps info about current file
=============
*/
-void PrintBSPFileSizes (void)
+void PrintBSPFileSizes(void)
{
- int numtextures = texdatasize ? ((dmiptexlump_t*)dtexdata)->nummiptex : 0;
- int totalmemory = 0;
-
- printf("\n");
- printf("Object names Objects/Maxobjs Memory / Maxmem Fullness\n" );
- printf("------------ --------------- --------------- --------\n" );
-
- totalmemory += ArrayUsage( "models", nummodels, MAX_MAP_MODELS, sizeof(dmodel_t) );
- totalmemory += ArrayUsage( "planes", numplanes, MAX_MAP_PLANES, sizeof(dplane_t) );
- totalmemory += ArrayUsage( "vertexes", numvertexes, MAX_MAP_VERTS, sizeof(dvertex_t) );
- totalmemory += ArrayUsage( "nodes", numnodes, MAX_MAP_NODES, sizeof(dnode_t) );
- totalmemory += ArrayUsage( "texinfos", numtexinfo, MAX_MAP_TEXINFO, sizeof(texinfo_t) );
- totalmemory += ArrayUsage( "faces", numfaces, MAX_MAP_FACES, sizeof(dface_t) );
- totalmemory += ArrayUsage( "clipnodes", numclipnodes, MAX_MAP_CLIPNODES, sizeof(dclipnode_t) );
- totalmemory += ArrayUsage( "leaves", numleafs, MAX_MAP_LEAFS, sizeof(dleaf_t) );
- totalmemory += ArrayUsage( "marksurfaces", nummarksurfaces, MAX_MAP_MARKSURFACES, sizeof(unsigned short) );
- totalmemory += ArrayUsage( "surfedges", numsurfedges, MAX_MAP_SURFEDGES, sizeof(int) );
- totalmemory += ArrayUsage( "edges", numedges, MAX_MAP_EDGES, sizeof(dedge_t) );
-
- totalmemory += GlobUsage( "texdata", texdatasize, MAX_MAP_MIPTEX );
- totalmemory += GlobUsage( "lightdata", lightdatasize, MAX_MAP_LIGHTING );
- totalmemory += GlobUsage( "visdata", visdatasize, MAX_MAP_VISIBILITY );
- totalmemory += GlobUsage( "entdata", entdatasize, MAX_MAP_ENTSTRING );
-
- printf( "=== Total BSP file data space used: %d bytes ===\n", totalmemory );
+ int numtextures = texdatasize ? ((dmiptexlump_t*)dtexdata)->nummiptex : 0;
+ int totalmemory = 0;
+
+ printf("\n");
+ printf("Object names Objects/Maxobjs Memory / Maxmem Fullness\n");
+ printf("------------ --------------- --------------- --------\n");
+
+ totalmemory += ArrayUsage("models", nummodels, MAX_MAP_MODELS, sizeof(dmodel_t));
+ totalmemory += ArrayUsage("planes", numplanes, MAX_MAP_PLANES, sizeof(dplane_t));
+ totalmemory += ArrayUsage("vertexes", numvertexes, MAX_MAP_VERTS, sizeof(dvertex_t));
+ totalmemory += ArrayUsage("nodes", numnodes, MAX_MAP_NODES, sizeof(dnode_t));
+ totalmemory += ArrayUsage("texinfos", numtexinfo, MAX_MAP_TEXINFO, sizeof(texinfo_t));
+ totalmemory += ArrayUsage("faces", numfaces, MAX_MAP_FACES, sizeof(dface_t));
+ totalmemory += ArrayUsage("clipnodes", numclipnodes, MAX_MAP_CLIPNODES, sizeof(dclipnode_t));
+ totalmemory += ArrayUsage("leaves", numleafs, MAX_MAP_LEAFS, sizeof(dleaf_t));
+ totalmemory += ArrayUsage("marksurfaces", nummarksurfaces, MAX_MAP_MARKSURFACES, sizeof(unsigned short));
+ totalmemory += ArrayUsage("surfedges", numsurfedges, MAX_MAP_SURFEDGES, sizeof(int));
+ totalmemory += ArrayUsage("edges", numedges, MAX_MAP_EDGES, sizeof(dedge_t));
+
+ totalmemory += GlobUsage("texdata", texdatasize, MAX_MAP_MIPTEX);
+ totalmemory += GlobUsage("lightdata", lightdatasize, MAX_MAP_LIGHTING);
+ totalmemory += GlobUsage("visdata", visdatasize, MAX_MAP_VISIBILITY);
+ totalmemory += GlobUsage("entdata", entdatasize, MAX_MAP_ENTSTRING);
+
+ printf("=== Total BSP file data space used: %d bytes ===\n", totalmemory);
}
-
/*
=================
ParseEpair
=================
*/
-epair_t *ParseEpair (void)
+epair_t* ParseEpair(void)
{
- epair_t *e;
+ epair_t* e;
- e = (epair_t *)malloc (sizeof(epair_t));
- memset (e, 0, sizeof(epair_t));
+ e = (epair_t*)malloc(sizeof(epair_t));
+ memset(e, 0, sizeof(epair_t));
- if (strlen(token) >= MAX_KEY-1)
- Error ("ParseEpar: token too long");
- e->key = copystring(token);
- GetToken (false);
- if (strlen(token) >= MAX_VALUE-1)
- Error ("ParseEpar: token too long");
- e->value = copystring(token);
+ if (strlen(token) >= MAX_KEY - 1)
+ Error("ParseEpar: token too long");
+ e->key = copystring(token);
+ GetToken(false);
+ if (strlen(token) >= MAX_VALUE - 1)
+ Error("ParseEpar: token too long");
+ e->value = copystring(token);
- return e;
+ return e;
}
-
void DumpEntity(int i)
{
- epair_t *e;
- entity_t *mapent;
-
- if ((i<0) || (i>=num_entities)) return ;
- mapent = &entities[i];
- e = mapent->epairs ;
- printf("Entity #%d:\n",i) ;
- while (e != NULL) {
- printf("\t%s = %s\n",e->key,e->value) ;
- e=e->next ;
- }
+ epair_t* e;
+ entity_t* mapent;
+
+ if ((i < 0) || (i >= num_entities)) return;
+ mapent = &entities[i];
+ e = mapent->epairs;
+ printf("Entity #%d:\n", i);
+ while (e != NULL) {
+ printf("\t%s = %s\n", e->key, e->value);
+ e = e->next;
+ }
}
/*
@@ -614,35 +607,35 @@ void DumpEntity(int i)
ParseEntity
================
*/
-qboolean ParseEntity (void)
+qboolean ParseEntity(void)
{
- epair_t *e;
- entity_t *mapent;
+ epair_t* e;
+ entity_t* mapent;
- if (!GetToken (true))
- return false;
+ if (!GetToken(true))
+ return false;
- if (strcmp (token, "{") )
- Error ("ParseEntity: { not found");
+ if (strcmp(token, "{"))
+ Error("ParseEntity: { not found");
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error("num_entities == MAX_MAP_ENTITIES");
- mapent = &entities[num_entities];
- num_entities++;
+ mapent = &entities[num_entities];
+ num_entities++;
- do
- {
- if (!GetToken (true))
- Error ("ParseEntity: EOF without closing brace");
- if (!strcmp (token, "}") )
- break;
- e = ParseEpair ();
- e->next = mapent->epairs;
- mapent->epairs = e;
- } while (1);
+ do
+ {
+ if (!GetToken(true))
+ Error("ParseEntity: EOF without closing brace");
+ if (!strcmp(token, "}"))
+ break;
+ e = ParseEpair();
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ } while (1);
- return true;
+ return true;
}
/*
@@ -652,17 +645,16 @@ ParseEntities
Parses the dentdata string into entities
================
*/
-void ParseEntities (void)
+void ParseEntities(void)
{
- num_entities = 0;
- ParseFromMemory (dentdata, entdatasize);
+ num_entities = 0;
+ ParseFromMemory(dentdata, entdatasize);
- while (ParseEntity ())
- {
- }
+ while (ParseEntity())
+ {
+ }
}
-
/*
================
UnparseEntities
@@ -670,211 +662,209 @@ UnparseEntities
Generates the dentdata string from all the entities
================
*/
-void UnparseEntities (void)
+void UnparseEntities(void)
{
- char *buf, *end;
- epair_t *ep;
- char line[2048];
- int i;
-
- buf = dentdata;
- end = buf;
- *end = 0;
-
- for (i=0 ; inext)
- {
- sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
- strcat (end, line);
- end += strlen(line);
- }
- strcat (end,"}\n");
- end += 2;
-
- if (end > buf + MAX_MAP_ENTSTRING)
- Error ("Entity text too long");
- }
- entdatasize = end - buf + 1;
+ char* buf, * end;
+ epair_t* ep;
+ char line[2048];
+ int i;
+
+ buf = dentdata;
+ end = buf;
+ *end = 0;
+
+ for (i = 0; i < num_entities; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ strcat(end, "{\n");
+ end += 2;
+
+ for (ep = entities[i].epairs; ep; ep = ep->next)
+ {
+ sprintf(line, "\"%s\" \"%s\"\n", ep->key, ep->value);
+ strcat(end, line);
+ end += strlen(line);
+ }
+ strcat(end, "}\n");
+ end += 2;
+
+ if (end > buf + MAX_MAP_ENTSTRING)
+ Error("Entity text too long");
+ }
+ entdatasize = end - buf + 1;
}
-void SetKeyValue (entity_t *ent, char *key, char *value)
+void SetKeyValue(entity_t* ent, char* key, char* value)
{
- epair_t *ep;
- epair_t *prev_ep = NULL;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- {
- if (!strcmp (ep->key, key) )
- {
- free (ep->value);
- ep->value = copystring(value);
- return;
- }
- }
-
- prev_ep = NULL;
- for (ep=ent->epairs ; ep ; prev_ep=ep, ep=ep->next)
- ; // get to the end of the linked list
-
- ep = (epair_t *)malloc (sizeof(*ep));
- memset(ep, 0, sizeof(ep));
-
- if (prev_ep)
- prev_ep->next = ep; // link it at the end
- else
- ent->epairs = ep; // link it at the beginning (first and only)
-
- ep->key = copystring(key);
- ep->value = copystring(value);
+ epair_t* ep;
+ epair_t* prev_ep = NULL;
+
+ for (ep = ent->epairs; ep; ep = ep->next)
+ {
+ if (!strcmp(ep->key, key))
+ {
+ free(ep->value);
+ ep->value = copystring(value);
+ return;
+ }
+ }
+
+ prev_ep = NULL;
+ for (ep = ent->epairs; ep; prev_ep = ep, ep = ep->next)
+ ; // get to the end of the linked list
+
+ ep = (epair_t*)malloc(sizeof(*ep));
+ memset(ep, 0, sizeof(ep));
+
+ if (prev_ep)
+ prev_ep->next = ep; // link it at the end
+ else
+ ent->epairs = ep; // link it at the beginning (first and only)
+
+ ep->key = copystring(key);
+ ep->value = copystring(value);
}
-void RemoveKey(entity_t *ent, char *key)
+void RemoveKey(entity_t* ent, char* key)
{
- epair_t *ep;
- epair_t *prev_ep = NULL;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- {
- if (!strcmp (ep->key, key) )
- {
- free (ep->value);
- free (ep->key);
- if (prev_ep)
- {
- prev_ep->next = ep->next;
- free(ep);
- }
- else
- {
- ent->epairs = ep->next;
- free(ep);
- }
- return;
- }
- prev_ep = ep;
- }
+ epair_t* ep;
+ epair_t* prev_ep = NULL;
+
+ for (ep = ent->epairs; ep; ep = ep->next)
+ {
+ if (!strcmp(ep->key, key))
+ {
+ free(ep->value);
+ free(ep->key);
+ if (prev_ep)
+ {
+ prev_ep->next = ep->next;
+ free(ep);
+ }
+ else
+ {
+ ent->epairs = ep->next;
+ free(ep);
+ }
+ return;
+ }
+ prev_ep = ep;
+ }
}
-int FindEntityByClassname(int index, const char *classname)
+int FindEntityByClassname(int index, const char* classname)
{
- epair_t *ep;
+ epair_t* ep;
- // index should be -1 to start at first entity...
- index++;
+ // index should be -1 to start at first entity...
+ index++;
- while (index < num_entities)
- {
- ep = entities[index].epairs;
+ while (index < num_entities)
+ {
+ ep = entities[index].epairs;
- while (ep)
- {
- if ((strcmp(ep->key, "classname") == 0) &&
- (strcmp(ep->value, classname) == 0))
- {
- return index;
- }
+ while (ep)
+ {
+ if ((strcmp(ep->key, "classname") == 0) &&
+ (strcmp(ep->value, classname) == 0))
+ {
+ return index;
+ }
- ep = ep->next;
- }
+ ep = ep->next;
+ }
- index ++;
- }
+ index++;
+ }
- return -1; // entity not found
+ return -1; // entity not found
}
-int FindEntityByWildcard(int index, const char *classname, int length)
+int FindEntityByWildcard(int index, const char* classname, int length)
{
- epair_t *ep;
+ epair_t* ep;
- // index should be -1 to start at first entity...
- index++;
+ // index should be -1 to start at first entity...
+ index++;
- while (index < num_entities)
- {
- ep = entities[index].epairs;
+ while (index < num_entities)
+ {
+ ep = entities[index].epairs;
- while (ep)
- {
- if ((strcmp(ep->key, "classname") == 0) &&
- (strncmp(ep->value, classname, length) == 0))
- {
- return index;
- }
+ while (ep)
+ {
+ if ((strcmp(ep->key, "classname") == 0) &&
+ (strncmp(ep->value, classname, length) == 0))
+ {
+ return index;
+ }
- ep = ep->next;
- }
+ ep = ep->next;
+ }
- index ++;
- }
+ index++;
+ }
- return -1; // entity not found
+ return -1; // entity not found
}
-char *ValueForKey (entity_t *ent, char *key)
+char* ValueForKey(entity_t* ent, char* key)
{
- epair_t *ep;
+ epair_t* ep;
- for (ep=ent->epairs ; ep ; ep=ep->next)
- if (!strcmp (ep->key, key) )
- return ep->value;
- return "";
+ for (ep = ent->epairs; ep; ep = ep->next)
+ if (!strcmp(ep->key, key))
+ return ep->value;
+ return "";
}
-vec_t FloatForKey (entity_t *ent, char *key)
+vec_t FloatForKey(entity_t* ent, char* key)
{
- char *k;
+ char* k;
- k = ValueForKey (ent, key);
- return (float)atof(k);
+ k = ValueForKey(ent, key);
+ return (float)atof(k);
}
-void GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
+void GetVectorForKey(entity_t* ent, char* key, vec3_t vec)
{
- char *k;
- double v1, v2, v3;
-
- k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = v3 = 0;
- sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
- vec[0] = (float)v1;
- vec[1] = (float)v2;
- vec[2] = (float)v3;
+ char* k;
+ double v1, v2, v3;
+
+ k = ValueForKey(ent, key);
+ // scanf into doubles, then assign, so it is vec_t size independent
+ v1 = v2 = v3 = 0;
+ sscanf(k, "%lf %lf %lf", &v1, &v2, &v3);
+ vec[0] = (float)v1;
+ vec[1] = (float)v2;
+ vec[2] = (float)v3;
}
-
void FreeEntities(void)
{
- int i;
- epair_t *pEpair, *pEpairNext;
-
- for (i=0; i < num_entities; i++)
- {
- pEpair = entities[i].epairs;
-
- while (pEpair)
- {
- pEpairNext = pEpair->next;
- free(pEpair->key);
- free(pEpair->value);
- free(pEpair);
- pEpair = pEpairNext;
- }
-
-// num_entities = 0; EVY
- }
- num_entities = 0; // EVY: should rather be here
-
- for (i=0; i < MAX_MAP_ENTITIES; i++)
- entities[i].epairs = NULL;
-}
-
+ int i;
+ epair_t* pEpair, * pEpairNext;
+
+ for (i = 0; i < num_entities; i++)
+ {
+ pEpair = entities[i].epairs;
+
+ while (pEpair)
+ {
+ pEpairNext = pEpair->next;
+ free(pEpair->key);
+ free(pEpair->value);
+ free(pEpair);
+ pEpair = pEpairNext;
+ }
+
+ // num_entities = 0; EVY
+ }
+ num_entities = 0; // EVY: should rather be here
+
+ for (i = 0; i < MAX_MAP_ENTITIES; i++)
+ entities[i].epairs = NULL;
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/bspfile.h b/Bsp2Rbn/bspfile.h
index 4f015ac..8aef463 100644
--- a/Bsp2Rbn/bspfile.h
+++ b/Bsp2Rbn/bspfile.h
@@ -1,339 +1,321 @@
-/***
-*
-* Copyright (c) 1998, Valve LLC. All rights reserved.
-*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
-* All Rights Reserved.
-*
-****/
-
-#ifndef __CMDLIB__
-#include "cmdlib.h"
-#endif
-
-#ifndef BSPFILE_H
-#define BSPFILE_H
-
-
-// upper design bounds
-
-#define MAX_MAP_HULLS 4
-
-#define MAX_MAP_MODELS 400
-#define MAX_MAP_BRUSHES 4096
-#define MAX_MAP_ENTITIES 1024
-#define MAX_MAP_ENTSTRING (128*1024)
-
-#define MAX_MAP_PLANES 32767
-#define MAX_MAP_NODES 32767 // because negative shorts are contents
-#define MAX_MAP_CLIPNODES 32767 //
-#define MAX_MAP_LEAFS 8192
-#define MAX_MAP_VERTS 65535
-#define MAX_MAP_FACES 65535
-#define MAX_MAP_MARKSURFACES 65535
-#define MAX_MAP_TEXINFO 8192
-#define MAX_MAP_EDGES 256000
-#define MAX_MAP_SURFEDGES 512000
-#define MAX_MAP_TEXTURES 512
-#define MAX_MAP_MIPTEX 0x200000
-#define MAX_MAP_LIGHTING 0x200000
-#define MAX_MAP_VISIBILITY 0x200000
-
-#define MAX_MAP_PORTALS 65536
-
-// key / value pair sizes
-
-#define MAX_KEY 32
-#define MAX_VALUE 4096
-
-//=============================================================================
-
-
-#define BSPVERSION 30
-#define TOOLVERSION 2
-
-
-typedef struct
-{
- int fileofs, filelen;
-} lump_t;
-
-#define LUMP_ENTITIES 0
-#define LUMP_PLANES 1
-#define LUMP_TEXTURES 2
-#define LUMP_VERTEXES 3
-#define LUMP_VISIBILITY 4
-#define LUMP_NODES 5
-#define LUMP_TEXINFO 6
-#define LUMP_FACES 7
-#define LUMP_LIGHTING 8
-#define LUMP_CLIPNODES 9
-#define LUMP_LEAFS 10
-#define LUMP_MARKSURFACES 11
-#define LUMP_EDGES 12
-#define LUMP_SURFEDGES 13
-#define LUMP_MODELS 14
-
-#define HEADER_LUMPS 15
-
-typedef struct
-{
- float mins[3], maxs[3];
- float origin[3];
- int headnode[MAX_MAP_HULLS];
- int visleafs; // not including the solid leaf 0
- int firstface, numfaces;
-} dmodel_t;
-
-typedef struct
-{
- int version;
- lump_t lumps[HEADER_LUMPS];
-} dheader_t;
-
-typedef struct
-{
- int nummiptex;
- int dataofs[4]; // [nummiptex]
-} dmiptexlump_t;
-
-#define MIPLEVELS 4
-typedef struct miptex_s
-{
- char name[16];
- unsigned width, height;
- unsigned offsets[MIPLEVELS]; // four mip maps stored
-} miptex_t;
-
-
-typedef struct
-{
- float point[3];
-} dvertex_t;
-
-
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define PLANE_ANYX 3
-#define PLANE_ANYY 4
-#define PLANE_ANYZ 5
-
-typedef struct
-{
- float normal[3];
- float dist;
- int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} dplane_t;
-
-
-
-#define CONTENTS_EMPTY -1
-#define CONTENTS_SOLID -2
-#define CONTENTS_WATER -3
-#define CONTENTS_SLIME -4
-#define CONTENTS_LAVA -5
-#define CONTENTS_SKY -6
-#define CONTENTS_ORIGIN -7 // removed at csg time
-#define CONTENTS_CLIP -8 // changed to contents_solid
-
-#define CONTENTS_CURRENT_0 -9
-#define CONTENTS_CURRENT_90 -10
-#define CONTENTS_CURRENT_180 -11
-#define CONTENTS_CURRENT_270 -12
-#define CONTENTS_CURRENT_UP -13
-#define CONTENTS_CURRENT_DOWN -14
-
-#define CONTENTS_TRANSLUCENT -15
-
-// !!! if this is changed, it must be changed in asm_i386.h too !!!
-typedef struct
-{
- int planenum;
- short children[2]; // negative numbers are -(leafs+1), not nodes
- short mins[3]; // for sphere culling
- short maxs[3];
- unsigned short firstface;
- unsigned short numfaces; // counting both sides
-} dnode_t;
-
-typedef struct
-{
- int planenum;
- short children[2]; // negative numbers are contents
-} dclipnode_t;
-
-
-typedef struct texinfo_s
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int miptex;
- int flags;
-} texinfo_t;
-
-#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
- unsigned short v[2]; // vertex numbers
-} dedge_t;
-
-#define MAXLIGHTMAPS 4
-
-typedef struct
-{
- short planenum;
- short side;
-
- int firstedge; // we must support > 64k edges
- short numedges;
- short texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- int lightofs; // start of [numstyles*surfsize] samples
-} dface_t;
-
-
-
-#define AMBIENT_WATER 0
-#define AMBIENT_SKY 1
-#define AMBIENT_SLIME 2
-#define AMBIENT_LAVA 3
-
-#define NUM_AMBIENTS 4 // automatic ambient sounds
-
-// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
-// all other leafs need visibility info
-typedef struct
-{
- int contents;
- int visofs; // -1 = no visibility info
-
- short mins[3]; // for frustum culling
- short maxs[3];
-
- unsigned short firstmarksurface;
- unsigned short nummarksurfaces;
-
- byte ambient_level[NUM_AMBIENTS];
-} dleaf_t;
-
-
-//============================================================================
-
-
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-
-// the utilities get to be lazy and just use large static arrays
-
-// Make all of these dynamic for BSP_tool...
-
-extern int nummodels;
-extern dmodel_t *dmodels;
-
-extern int visdatasize;
-extern byte *dvisdata;
-
-extern int lightdatasize;
-extern byte *dlightdata;
-
-extern int texdatasize;
-extern byte *dtexdata;
-
-extern int entdatasize;
-extern char *dentdata;
-
-extern int numleafs;
-extern dleaf_t *dleafs;
-
-extern int numplanes;
-extern dplane_t *dplanes;
-
-extern int numvertexes;
-extern dvertex_t *dvertexes;
-
-extern int numnodes;
-extern dnode_t *dnodes;
-
-extern int numtexinfo;
-extern texinfo_t *texinfo;
-
-extern int numfaces;
-extern dface_t *dfaces;
-
-extern int numclipnodes;
-extern dclipnode_t *dclipnodes;
-
-extern int numedges;
-extern dedge_t *dedges;
-
-extern int nummarksurfaces;
-extern unsigned short *dmarksurfaces;
-
-extern int numsurfedges;
-extern int *dsurfedges;
-
-
-int FastChecksum(char *buffer, int bytes);
-
-void DecompressVis (byte *in, byte *decompressed);
-int CompressVis (byte *vis, byte *dest);
-
-void SwapBSPFile (qboolean todisk);
-int CopyLump (int lump, void **dest, int size);
-void LoadBSPFile (char *filename);
-void WriteBSPFile (char *filename);
-void PrintBSPFileSizes (void);
-
-
-//===============
-
-
-typedef struct epair_s
-{
- struct epair_s *next;
- char *key;
- char *value;
-} epair_t;
-
-typedef struct
-{
- vec3_t origin;
- int firstbrush;
- int numbrushes;
- epair_t *epairs;
-} entity_t;
-
-extern int num_entities;
-extern entity_t entities[MAX_MAP_ENTITIES];
-
-void ParseEntities (void);
-void DumpEntity(int i) ;
-void UnparseEntities (void);
-
-void SetKeyValue (entity_t *ent, char *key, char *value);
-void RemoveKey(entity_t *ent, char *key);
-int FindEntityByClassname(int index, const char *classname);
-int FindEntityByWildcard(int index, const char *classname, int length);
-char *ValueForKey (entity_t *ent, char *key);
-// will return "" if not present
-
-vec_t FloatForKey (entity_t *ent, char *key);
-void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
-
-epair_t *ParseEpair (void);
-
-void FreeEntities(void);
-
-
-#endif // BSPFILE_H
+/***
+*
+* Copyright (c) 1998, Valve LLC. All rights reserved.
+*
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+* All Rights Reserved.
+*
+****/
+#ifndef __CMDLIB__
+#include "cmdlib.h"
+#endif
+
+#ifndef BSPFILE_H
+#define BSPFILE_H
+
+// upper design bounds
+
+#define MAX_MAP_HULLS 4
+
+#define MAX_MAP_MODELS 400
+#define MAX_MAP_BRUSHES 4096
+#define MAX_MAP_ENTITIES 1024
+#define MAX_MAP_ENTSTRING (128*1024)
+
+#define MAX_MAP_PLANES 32767
+#define MAX_MAP_NODES 32767 // because negative shorts are contents
+#define MAX_MAP_CLIPNODES 32767 //
+#define MAX_MAP_LEAFS 8192
+#define MAX_MAP_VERTS 65535
+#define MAX_MAP_FACES 65535
+#define MAX_MAP_MARKSURFACES 65535
+#define MAX_MAP_TEXINFO 8192
+#define MAX_MAP_EDGES 256000
+#define MAX_MAP_SURFEDGES 512000
+#define MAX_MAP_TEXTURES 512
+#define MAX_MAP_MIPTEX 0x200000
+#define MAX_MAP_LIGHTING 0x200000
+#define MAX_MAP_VISIBILITY 0x200000
+
+#define MAX_MAP_PORTALS 65536
+
+// key / value pair sizes
+
+#define MAX_KEY 32
+#define MAX_VALUE 4096
+
+//=============================================================================
+
+#define BSPVERSION 30
+#define TOOLVERSION 2
+
+typedef struct
+{
+ int fileofs, filelen;
+} lump_t;
+
+#define LUMP_ENTITIES 0
+#define LUMP_PLANES 1
+#define LUMP_TEXTURES 2
+#define LUMP_VERTEXES 3
+#define LUMP_VISIBILITY 4
+#define LUMP_NODES 5
+#define LUMP_TEXINFO 6
+#define LUMP_FACES 7
+#define LUMP_LIGHTING 8
+#define LUMP_CLIPNODES 9
+#define LUMP_LEAFS 10
+#define LUMP_MARKSURFACES 11
+#define LUMP_EDGES 12
+#define LUMP_SURFEDGES 13
+#define LUMP_MODELS 14
+
+#define HEADER_LUMPS 15
+
+typedef struct
+{
+ float mins[3], maxs[3];
+ float origin[3];
+ int headnode[MAX_MAP_HULLS];
+ int visleafs; // not including the solid leaf 0
+ int firstface, numfaces;
+} dmodel_t;
+
+typedef struct
+{
+ int version;
+ lump_t lumps[HEADER_LUMPS];
+} dheader_t;
+
+typedef struct
+{
+ int nummiptex;
+ int dataofs[4]; // [nummiptex]
+} dmiptexlump_t;
+
+#define MIPLEVELS 4
+typedef struct miptex_s
+{
+ char name[16];
+ unsigned width, height;
+ unsigned offsets[MIPLEVELS]; // four mip maps stored
+} miptex_t;
+
+typedef struct
+{
+ float point[3];
+} dvertex_t;
+
+// 0-2 are axial planes
+#define PLANE_X 0
+#define PLANE_Y 1
+#define PLANE_Z 2
+
+// 3-5 are non-axial planes snapped to the nearest
+#define PLANE_ANYX 3
+#define PLANE_ANYY 4
+#define PLANE_ANYZ 5
+
+typedef struct
+{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+} dplane_t;
+
+#define CONTENTS_EMPTY -1
+#define CONTENTS_SOLID -2
+#define CONTENTS_WATER -3
+#define CONTENTS_SLIME -4
+#define CONTENTS_LAVA -5
+#define CONTENTS_SKY -6
+#define CONTENTS_ORIGIN -7 // removed at csg time
+#define CONTENTS_CLIP -8 // changed to contents_solid
+
+#define CONTENTS_CURRENT_0 -9
+#define CONTENTS_CURRENT_90 -10
+#define CONTENTS_CURRENT_180 -11
+#define CONTENTS_CURRENT_270 -12
+#define CONTENTS_CURRENT_UP -13
+#define CONTENTS_CURRENT_DOWN -14
+
+#define CONTENTS_TRANSLUCENT -15
+
+// !!! if this is changed, it must be changed in asm_i386.h too !!!
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for sphere culling
+ short maxs[3];
+ unsigned short firstface;
+ unsigned short numfaces; // counting both sides
+} dnode_t;
+
+typedef struct
+{
+ int planenum;
+ short children[2]; // negative numbers are contents
+} dclipnode_t;
+
+typedef struct texinfo_s
+{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int miptex;
+ int flags;
+} texinfo_t;
+
+#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
+
+// note that edge 0 is never used, because negative edge nums are used for
+// counterclockwise use of the edge in a face
+typedef struct
+{
+ unsigned short v[2]; // vertex numbers
+} dedge_t;
+
+#define MAXLIGHTMAPS 4
+
+typedef struct
+{
+ short planenum;
+ short side;
+
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+
+ // lighting info
+ byte styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+} dface_t;
+
+#define AMBIENT_WATER 0
+#define AMBIENT_SKY 1
+#define AMBIENT_SLIME 2
+#define AMBIENT_LAVA 3
+
+#define NUM_AMBIENTS 4 // automatic ambient sounds
+
+// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
+// all other leafs need visibility info
+typedef struct
+{
+ int contents;
+ int visofs; // -1 = no visibility info
+
+ short mins[3]; // for frustum culling
+ short maxs[3];
+
+ unsigned short firstmarksurface;
+ unsigned short nummarksurfaces;
+
+ byte ambient_level[NUM_AMBIENTS];
+} dleaf_t;
+
+//============================================================================
+
+#define ANGLE_UP -1
+#define ANGLE_DOWN -2
+
+// the utilities get to be lazy and just use large static arrays
+
+// Make all of these dynamic for BSP_tool...
+
+extern int nummodels;
+extern dmodel_t* dmodels;
+
+extern int visdatasize;
+extern byte* dvisdata;
+
+extern int lightdatasize;
+extern byte* dlightdata;
+
+extern int texdatasize;
+extern byte* dtexdata;
+
+extern int entdatasize;
+extern char* dentdata;
+
+extern int numleafs;
+extern dleaf_t* dleafs;
+
+extern int numplanes;
+extern dplane_t* dplanes;
+
+extern int numvertexes;
+extern dvertex_t* dvertexes;
+
+extern int numnodes;
+extern dnode_t* dnodes;
+
+extern int numtexinfo;
+extern texinfo_t* texinfo;
+
+extern int numfaces;
+extern dface_t* dfaces;
+
+extern int numclipnodes;
+extern dclipnode_t* dclipnodes;
+
+extern int numedges;
+extern dedge_t* dedges;
+
+extern int nummarksurfaces;
+extern unsigned short* dmarksurfaces;
+
+extern int numsurfedges;
+extern int* dsurfedges;
+
+int FastChecksum(char* buffer, int bytes);
+
+void DecompressVis(byte* in, byte* decompressed);
+int CompressVis(byte* vis, byte* dest);
+
+void SwapBSPFile(qboolean todisk);
+int CopyLump(int lump, void** dest, int size);
+void LoadBSPFile(char* filename);
+void WriteBSPFile(char* filename);
+void PrintBSPFileSizes(void);
+
+//===============
+
+typedef struct epair_s
+{
+ struct epair_s* next;
+ char* key;
+ char* value;
+} epair_t;
+
+typedef struct
+{
+ vec3_t origin;
+ int firstbrush;
+ int numbrushes;
+ epair_t* epairs;
+} entity_t;
+
+extern int num_entities;
+extern entity_t entities[MAX_MAP_ENTITIES];
+
+void ParseEntities(void);
+void DumpEntity(int i);
+void UnparseEntities(void);
+
+void SetKeyValue(entity_t* ent, char* key, char* value);
+void RemoveKey(entity_t* ent, char* key);
+int FindEntityByClassname(int index, const char* classname);
+int FindEntityByWildcard(int index, const char* classname, int length);
+char* ValueForKey(entity_t* ent, char* key);
+// will return "" if not present
+
+vec_t FloatForKey(entity_t* ent, char* key);
+void GetVectorForKey(entity_t* ent, char* key, vec3_t vec);
+
+epair_t* ParseEpair(void);
+
+void FreeEntities(void);
+
+#endif // BSPFILE_H
diff --git a/Bsp2Rbn/build.cpp b/Bsp2Rbn/build.cpp
index 881b47a..4629175 100644
--- a/Bsp2Rbn/build.cpp
+++ b/Bsp2Rbn/build.cpp
@@ -1,4 +1,4 @@
-char * Version = "0.9.7 of $Date$" ;
+char* Version = "0.9.7 of $Date$";
// $Log: build.cpp,v $
// Revision 1.6 2004/07/27 07:43:35 eric
@@ -17,4 +17,4 @@ char * Version = "0.9.7 of $Date$" ;
// Revision 1.3 2004/07/20 12:36:10 eric
// - bumped version to 0.9.3
// - it compiles eventually on Windows with mingw...
-//
+//
\ No newline at end of file
diff --git a/Bsp2Rbn/cmdlib.cpp b/Bsp2Rbn/cmdlib.cpp
index ec46971..204013d 100644
--- a/Bsp2Rbn/cmdlib.cpp
+++ b/Bsp2Rbn/cmdlib.cpp
@@ -2,8 +2,8 @@
*
* Copyright (c) 1998, Valve LLC. All rights reserved.
*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
****/
@@ -31,7 +31,7 @@
// set these before calling CheckParm
int myargc;
-char **myargv;
+char** myargv;
char com_token[1024];
qboolean com_eof;
@@ -39,7 +39,6 @@ qboolean com_eof;
qboolean archive;
char archivedir[1024];
-
/*
=================
Error
@@ -47,44 +46,43 @@ Error
For abnormal program terminations
=================
*/
-void Error (char *error, ...)
+void Error(char* error, ...)
{
- va_list argptr;
- char msg[256];
+ va_list argptr;
+ char msg[256];
- va_start (argptr, error);
- vsprintf (msg, error, argptr);
- va_end (argptr);
+ va_start(argptr, error);
+ vsprintf(msg, error, argptr);
+ va_end(argptr);
#ifdef __linux__
- printf("\n************ ERROR ************\n");
- printf("%s\n", msg);
+ printf("\n************ ERROR ************\n");
+ printf("%s\n", msg);
#else
- char input[1];
+ char input[1];
- printf("\n************ ERROR ************\n");
- printf("%s\n", msg);
- printf("\nPress to exit\n");
- gets(input);
+ printf("\n************ ERROR ************\n");
+ printf("%s\n", msg);
+ printf("\nPress to exit\n");
+ gets(input);
#endif
- exit (1);
+ exit(1);
}
// only printf if in verbose mode
qboolean verbose = false;
-void qprintf (char *format, ...)
+void qprintf(char* format, ...)
{
- va_list argptr;
+ va_list argptr;
- if (!verbose)
- return;
- va_start (argptr,format);
- vprintf (format,argptr);
- va_end (argptr);
+ if (!verbose)
+ return;
+ va_start(argptr, format);
+ vprintf(format, argptr);
+ va_end(argptr);
}
-
/*
qdir will hold the path up to the quake directory, including the slash
@@ -96,208 +94,203 @@ gamedir will hold qdir + the game directory (id1, id2, etc)
*/
-char qproject[ 1024 ]={'\0'};
-char qdir[1024]={'\0'};
-char gamedir[1024]={'\0'};
+char qproject[1024] = { '\0' };
+char qdir[1024] = { '\0' };
+char gamedir[1024] = { '\0' };
-void SetQdirFromPath (char *path)
+void SetQdirFromPath(char* path)
{
#ifndef OLD_BOGUS_PATH_CODE
- if ( qproject[0]=='\0' )
- {
- if ( getenv("QPROJECT") )
- {
- char c = qproject[ strlen(qproject)-1 ];
- strcpy( qproject, getenv("QPROJECT") );
- if ( !PATHSEPARATOR( c ) )
- strcat( qproject, "\\" );
- }
- else
- strcpy( qproject, "quiver\\" );
- }
- if ( qproject[0] != '\\' && qproject[0] != '/' && qproject[1] != ':' )
- {
- strcpy( qdir, "\\" );
- }
-
- strcat( qdir, qproject );
- strcpy( gamedir, qdir );
- strcat( gamedir, "\\valve\\" );
+ if (qproject[0] == '\0')
+ {
+ if (getenv("QPROJECT"))
+ {
+ char c = qproject[strlen(qproject) - 1];
+ strcpy(qproject, getenv("QPROJECT"));
+ if (!PATHSEPARATOR(c))
+ strcat(qproject, "\\");
+ }
+ else
+ strcpy(qproject, "quiver\\");
+ }
+ if (qproject[0] != '\\' && qproject[0] != '/' && qproject[1] != ':')
+ {
+ strcpy(qdir, "\\");
+ }
+
+ strcat(qdir, qproject);
+ strcpy(gamedir, qdir);
+ strcat(gamedir, "\\valve\\");
#else
- char temp[1024];
- char *c;
+ char temp[1024];
+ char* c;
- if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
- { // path is partial
- Q_getwd (temp);
- strcat (temp, path);
- path = temp;
- }
+ if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
+ { // path is partial
+ Q_getwd(temp);
+ strcat(temp, path);
+ path = temp;
+ }
-// search for "quake" or quiver in path
- if( !qproject[0] )
- {
- char *pszProj;
+ // search for "quake" or quiver in path
+ if (!qproject[0])
+ {
+ char* pszProj;
- pszProj = getenv("QPROJECT");
+ pszProj = getenv("QPROJECT");
- if (pszProj != NULL)
- strcpy(qproject, pszProj);
- else
- strcpy(qproject, "quiver");
- }
+ if (pszProj != NULL)
+ strcpy(qproject, pszProj);
+ else
+ strcpy(qproject, "quiver");
+ }
try_again:
- for (c=path ; *c ; c++)
- {
- int iSize = 0;
-
- if (!Q_strncasecmp( c, qproject, strlen( qproject ) ) )
- iSize = strlen( qproject ) + 1;
-
- if (iSize > 0)
- {
- strncpy (qdir, path, c + iSize - path);
- printf ("qdir: %s\n", qdir);
- c += iSize;
- while (*c)
- {
- if (*c == '/' || *c == '\\')
- {
- strncpy (gamedir, path, c+1-path);
- printf ("gamedir: %s\n", gamedir);
- return;
- }
- c++;
- }
- Error ("No gamedir in %s", path);
- return;
- }
- }
-
- if (!strcmp(qproject, "quiver"))
- {
- strcpy(qproject, "prospero");
- goto try_again;
- }
-
- Error ("SetQdirFromPath: no '%s' in %s", qproject, path);
+ for (c = path; *c; c++)
+ {
+ int iSize = 0;
+
+ if (!Q_strncasecmp(c, qproject, strlen(qproject)))
+ iSize = strlen(qproject) + 1;
+
+ if (iSize > 0)
+ {
+ strncpy(qdir, path, c + iSize - path);
+ printf("qdir: %s\n", qdir);
+ c += iSize;
+ while (*c)
+ {
+ if (*c == '/' || *c == '\\')
+ {
+ strncpy(gamedir, path, c + 1 - path);
+ printf("gamedir: %s\n", gamedir);
+ return;
+ }
+ c++;
+ }
+ Error("No gamedir in %s", path);
+ return;
+ }
+ }
+
+ if (!strcmp(qproject, "quiver"))
+ {
+ strcpy(qproject, "prospero");
+ goto try_again;
+ }
+
+ Error("SetQdirFromPath: no '%s' in %s", qproject, path);
#endif
}
-
-char *ExpandArg (char *path)
+char* ExpandArg(char* path)
{
- static char full[1024];
-
- if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
- {
- Q_getwd (full);
- strcat (full, path);
- }
- else
- strcpy (full, path);
- return full;
+ static char full[1024];
+
+ if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
+ {
+ Q_getwd(full);
+ strcat(full, path);
+ }
+ else
+ strcpy(full, path);
+ return full;
}
-char *ExpandPath (char *path)
+char* ExpandPath(char* path)
{
- char *psz;
- static char full[1024];
- if (!qdir)
- Error ("ExpandPath called without qdir set");
- if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
- return path;
- psz = strstr(path, qdir);
- if (psz)
- strcpy(full, path);
- else
- sprintf (full, "%s%s", qdir, path);
-
- return full;
+ char* psz;
+ static char full[1024];
+ if (!qdir)
+ Error("ExpandPath called without qdir set");
+ if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
+ return path;
+ psz = strstr(path, qdir);
+ if (psz)
+ strcpy(full, path);
+ else
+ sprintf(full, "%s%s", qdir, path);
+
+ return full;
}
-char *ExpandPathAndArchive (char *path)
+char* ExpandPathAndArchive(char* path)
{
- char *expanded;
- char archivename[1024];
+ char* expanded;
+ char archivename[1024];
- expanded = ExpandPath (path);
+ expanded = ExpandPath(path);
- if (archive)
- {
- sprintf (archivename, "%s/%s", archivedir, path);
- QCopyFile (expanded, archivename);
- }
- return expanded;
+ if (archive)
+ {
+ sprintf(archivename, "%s/%s", archivedir, path);
+ QCopyFile(expanded, archivename);
+ }
+ return expanded;
}
-
-char *copystring(char *s)
+char* copystring(char* s)
{
- char *b;
- b = (char *)malloc(strlen(s)+1);
- strcpy (b, s);
- return b;
+ char* b;
+ b = (char*)malloc(strlen(s) + 1);
+ strcpy(b, s);
+ return b;
}
-
-
/*
================
I_FloatTime
================
*/
-double I_FloatTime (void)
+double I_FloatTime(void)
{
- time_t t;
-
- time (&t);
-
- return t;
+ time_t t;
+
+ time(&t);
+
+ return t;
#if 0
-// more precise, less portable
- struct timeval tp;
- struct timezone tzp;
- static int secbase;
-
- gettimeofday(&tp, &tzp);
-
- if (!secbase)
- {
- secbase = tp.tv_sec;
- return tp.tv_usec/1000000.0;
- }
-
- return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
+ // more precise, less portable
+ struct timeval tp;
+ struct timezone tzp;
+ static int secbase;
+
+ gettimeofday(&tp, &tzp);
+
+ if (!secbase)
+ {
+ secbase = tp.tv_sec;
+ return tp.tv_usec / 1000000.0;
+ }
+
+ return (tp.tv_sec - secbase) + tp.tv_usec / 1000000.0;
#endif
}
-void Q_getwd (char *out)
+void Q_getwd(char* out)
{
#ifndef __linux__
- _getcwd (out, 256);
- strcat (out, "\\");
+ _getcwd(out, 256);
+ strcat(out, "\\");
#else
- getcwd (out, 256);
+ getcwd(out, 256);
#endif
}
-
-void Q_mkdir (char *path)
+void Q_mkdir(char* path)
{
#ifndef __linux__
- if (_mkdir (path) != -1)
- return;
+ if (_mkdir(path) != -1)
+ return;
#else
- if (mkdir (path, 0777) != -1)
- return;
+ if (mkdir(path, 0777) != -1)
+ return;
#endif
- if (errno != EEXIST)
- Error ("mkdir %s: %s",path, strerror(errno));
+ if (errno != EEXIST)
+ Error("mkdir %s: %s", path, strerror(errno));
}
/*
@@ -307,17 +300,15 @@ FileTime
returns -1 if not present
============
*/
-int FileTime (char *path)
+int FileTime(char* path)
{
- struct stat buf;
-
- if (stat (path,&buf) == -1)
- return -1;
-
- return buf.st_mtime;
-}
+ struct stat buf;
+ if (stat(path, &buf) == -1)
+ return -1;
+ return buf.st_mtime;
+}
/*
==============
@@ -326,148 +317,143 @@ COM_Parse
Parse a token out of a string (into global: char com_token[1024])
==============
*/
-char *COM_Parse (char *data)
-{
- int c;
- int len;
-
- len = 0;
- com_token[0] = 0;
-
- if (!data)
- return NULL;
-
-// skip whitespace
-skipwhite:
- while ( (c = *data) <= ' ')
- {
- if (c == 0)
- {
- com_eof = true;
- return NULL; // end of file;
- }
- data++;
- }
-
-// skip // comments
- if (c=='/' && data[1] == '/')
- {
- while (*data && *data != '\n')
- data++;
- goto skipwhite;
- }
-
-
-// handle quoted strings specially
- if (c == '\"')
- {
- data++;
- do
- {
- c = *data++;
- if (c=='\"')
- {
- com_token[len] = 0;
- return data;
- }
- com_token[len] = c;
- len++;
- } while (1);
- }
-
-// parse single characters
- if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
- {
- com_token[len] = c;
- len++;
- com_token[len] = 0;
- return data+1;
- }
-
-// parse a regular word
- do
- {
- com_token[len] = c;
- data++;
- len++;
- c = *data;
- if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
- break;
- } while (c>32);
-
- com_token[len] = 0;
- return data;
-}
-
-
-int Q_strncasecmp (char *s1, char *s2, int n)
+char* COM_Parse(char* data)
{
- int c1, c2;
-
- while (1)
- {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--)
- return 0; // strings are equal until end point
-
- if (c1 != c2)
- {
- if (c1 >= 'a' && c1 <= 'z')
- c1 -= ('a' - 'A');
- if (c2 >= 'a' && c2 <= 'z')
- c2 -= ('a' - 'A');
- if (c1 != c2)
- return -1; // strings not equal
- }
- if (!c1)
- return 0; // strings are equal
- }
-
- return -1;
-}
-
-int Q_strcasecmp (char *s1, char *s2)
-{
- return Q_strncasecmp (s1, s2, 99999);
-}
+ int c;
+ int len;
+ len = 0;
+ com_token[0] = 0;
-char *strupr (char *start)
-{
- char *in;
- in = start;
- while (*in)
- {
- *in = toupper(*in);
- in++;
- }
- return start;
-}
+ if (!data)
+ return NULL;
-char *strlower (char *start)
-{
- char *in;
- in = start;
- while (*in)
- {
- *in = tolower(*in);
- in++;
- }
- return start;
+ // skip whitespace
+skipwhite:
+ while ((c = *data) <= ' ')
+ {
+ if (c == 0)
+ {
+ com_eof = true;
+ return NULL; // end of file;
+ }
+ data++;
+ }
+
+ // skip // comments
+ if (c == '/' && data[1] == '/')
+ {
+ while (*data && *data != '\n')
+ data++;
+ goto skipwhite;
+ }
+
+ // handle quoted strings specially
+ if (c == '\"')
+ {
+ data++;
+ do
+ {
+ c = *data++;
+ if (c == '\"')
+ {
+ com_token[len] = 0;
+ return data;
+ }
+ com_token[len] = c;
+ len++;
+ } while (1);
+ }
+
+ // parse single characters
+ if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':')
+ {
+ com_token[len] = c;
+ len++;
+ com_token[len] = 0;
+ return data + 1;
+ }
+
+ // parse a regular word
+ do
+ {
+ com_token[len] = c;
+ data++;
+ len++;
+ c = *data;
+ if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':')
+ break;
+ } while (c > 32);
+
+ com_token[len] = 0;
+ return data;
+}
+
+int Q_strncasecmp(char* s1, char* s2, int n)
+{
+ int c1, c2;
+
+ while (1)
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--)
+ return 0; // strings are equal until end point
+
+ if (c1 != c2)
+ {
+ if (c1 >= 'a' && c1 <= 'z')
+ c1 -= ('a' - 'A');
+ if (c2 >= 'a' && c2 <= 'z')
+ c2 -= ('a' - 'A');
+ if (c1 != c2)
+ return -1; // strings not equal
+ }
+ if (!c1)
+ return 0; // strings are equal
+ }
+
+ return -1;
+}
+
+int Q_strcasecmp(char* s1, char* s2)
+{
+ return Q_strncasecmp(s1, s2, 99999);
+}
+
+char* strupr(char* start)
+{
+ char* in;
+ in = start;
+ while (*in)
+ {
+ *in = toupper(*in);
+ in++;
+ }
+ return start;
+}
+
+char* strlower(char* start)
+{
+ char* in;
+ in = start;
+ while (*in)
+ {
+ *in = tolower(*in);
+ in++;
+ }
+ return start;
}
-
/*
=============================================================================
- MISC FUNCTIONS
+ MISC FUNCTIONS
=============================================================================
*/
-
/*
=================
CheckParm
@@ -476,283 +462,267 @@ Checks for the given parameter in the program's command line arguments
Returns the argument number (1 to argc-1) or 0 if not present
=================
*/
-int CheckParm (char *check)
+int CheckParm(char* check)
{
- int i;
+ int i;
- for (i = 1;i 0 && !PATHSEPARATOR(path[length]))
- length--;
- path[length] = 0;
+ length = strlen(path) - 1;
+ while (length > 0 && !PATHSEPARATOR(path[length]))
+ length--;
+ path[length] = 0;
}
-void StripExtension (char *path)
+void StripExtension(char* path)
{
- int length;
-
- length = strlen(path)-1;
- while (length > 0 && path[length] != '.')
- {
- length--;
- if (path[length] == '/')
- return; // no extension
- }
- if (length)
- path[length] = 0;
-}
+ int length;
+ length = strlen(path) - 1;
+ while (length > 0 && path[length] != '.')
+ {
+ length--;
+ if (path[length] == '/')
+ return; // no extension
+ }
+ if (length)
+ path[length] = 0;
+}
/*
====================
Extract file parts
====================
*/
-void ExtractFilePath (char *path, char *dest)
+void ExtractFilePath(char* path, char* dest)
{
- char *src;
+ char* src;
- src = path + strlen(path) - 1;
+ src = path + strlen(path) - 1;
-//
-// back up until a \ or the start
-//
- while (src != path && !PATHSEPARATOR(*(src-1)))
- src--;
+ //
+ // back up until a \ or the start
+ //
+ while (src != path && !PATHSEPARATOR(*(src - 1)))
+ src--;
- memcpy (dest, path, src-path);
- dest[src-path] = 0;
+ memcpy(dest, path, src - path);
+ dest[src - path] = 0;
}
-void ExtractFileBase (char *path, char *dest)
+void ExtractFileBase(char* path, char* dest)
{
- char *src;
+ char* src;
- src = path + strlen(path) - 1;
+ src = path + strlen(path) - 1;
-//
-// back up until a \ or the start
-//
- while (src != path && !PATHSEPARATOR(*(src-1)))
- src--;
-
- while (*src && *src != '.')
- {
- *dest++ = *src++;
- }
- *dest = 0;
+ //
+ // back up until a \ or the start
+ //
+ while (src != path && !PATHSEPARATOR(*(src - 1)))
+ src--;
+
+ while (*src && *src != '.')
+ {
+ *dest++ = *src++;
+ }
+ *dest = 0;
}
-void ExtractFileExtension (char *path, char *dest)
+void ExtractFileExtension(char* path, char* dest)
{
- char *src;
+ char* src;
- src = path + strlen(path) - 1;
+ src = path + strlen(path) - 1;
-//
-// back up until a . or the start
-//
- while (src != path && *(src-1) != '.')
- src--;
- if (src == path)
- {
- *dest = 0; // no extension
- return;
- }
-
- strcpy (dest,src);
-}
+ //
+ // back up until a . or the start
+ //
+ while (src != path && *(src - 1) != '.')
+ src--;
+ if (src == path)
+ {
+ *dest = 0; // no extension
+ return;
+ }
+ strcpy(dest, src);
+}
/*
==============
ParseNum / ParseHex
==============
*/
-int ParseHex (char *hex)
+int ParseHex(char* hex)
{
- char *str;
- int num;
-
- num = 0;
- str = hex;
-
- while (*str)
- {
- num <<= 4;
- if (*str >= '0' && *str <= '9')
- num += *str-'0';
- else if (*str >= 'a' && *str <= 'f')
- num += 10 + *str-'a';
- else if (*str >= 'A' && *str <= 'F')
- num += 10 + *str-'A';
- else
- Error ("Bad hex number: %s",hex);
- str++;
- }
-
- return num;
-}
+ char* str;
+ int num;
+ num = 0;
+ str = hex;
-int ParseNum (char *str)
-{
- if (str[0] == '$')
- return ParseHex (str+1);
- if (str[0] == '0' && str[1] == 'x')
- return ParseHex (str+2);
- return atol (str);
-}
+ while (*str)
+ {
+ num <<= 4;
+ if (*str >= '0' && *str <= '9')
+ num += *str - '0';
+ else if (*str >= 'a' && *str <= 'f')
+ num += 10 + *str - 'a';
+ else if (*str >= 'A' && *str <= 'F')
+ num += 10 + *str - 'A';
+ else
+ Error("Bad hex number: %s", hex);
+ str++;
+ }
+ return num;
+}
+int ParseNum(char* str)
+{
+ if (str[0] == '$')
+ return ParseHex(str + 1);
+ if (str[0] == '0' && str[1] == 'x')
+ return ParseHex(str + 2);
+ return atol(str);
+}
/*
============================================================================
- BYTE ORDER FUNCTIONS
+ BYTE ORDER FUNCTIONS
============================================================================
*/
@@ -763,120 +733,112 @@ int ParseNum (char *str)
#ifdef __BIG_ENDIAN__
-short LittleShort (short l)
+short LittleShort(short l)
{
- byte b1,b2;
+ byte b1, b2;
- b1 = l&255;
- b2 = (l>>8)&255;
+ b1 = l & 255;
+ b2 = (l >> 8) & 255;
- return (b1<<8) + b2;
+ return (b1 << 8) + b2;
}
-short BigShort (short l)
+short BigShort(short l)
{
- return l;
+ return l;
}
-
-int LittleLong (int l)
+int LittleLong(int l)
{
- byte b1,b2,b3,b4;
+ byte b1, b2, b3, b4;
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
+ b1 = l & 255;
+ b2 = (l >> 8) & 255;
+ b3 = (l >> 16) & 255;
+ b4 = (l >> 24) & 255;
- return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+ return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4;
}
-int BigLong (int l)
+int BigLong(int l)
{
- return l;
+ return l;
}
-
-float LittleFloat (float l)
+float LittleFloat(float l)
{
- union {byte b[4]; float f;} in, out;
-
- in.f = l;
- out.b[0] = in.b[3];
- out.b[1] = in.b[2];
- out.b[2] = in.b[1];
- out.b[3] = in.b[0];
-
- return out.f;
+ union { byte b[4]; float f; } in, out;
+
+ in.f = l;
+ out.b[0] = in.b[3];
+ out.b[1] = in.b[2];
+ out.b[2] = in.b[1];
+ out.b[3] = in.b[0];
+
+ return out.f;
}
-float BigFloat (float l)
+float BigFloat(float l)
{
- return l;
+ return l;
}
-
#else
-
-short BigShort (short l)
+short BigShort(short l)
{
- byte b1,b2;
+ byte b1, b2;
- b1 = l&255;
- b2 = (l>>8)&255;
+ b1 = l & 255;
+ b2 = (l >> 8) & 255;
- return (b1<<8) + b2;
+ return (b1 << 8) + b2;
}
-short LittleShort (short l)
+short LittleShort(short l)
{
- return l;
+ return l;
}
-
-int BigLong (int l)
+int BigLong(int l)
{
- byte b1,b2,b3,b4;
+ byte b1, b2, b3, b4;
- b1 = l&255;
- b2 = (l>>8)&255;
- b3 = (l>>16)&255;
- b4 = (l>>24)&255;
+ b1 = l & 255;
+ b2 = (l >> 8) & 255;
+ b3 = (l >> 16) & 255;
+ b4 = (l >> 24) & 255;
- return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+ return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4;
}
-int LittleLong (int l)
+int LittleLong(int l)
{
- return l;
+ return l;
}
-float BigFloat (float l)
+float BigFloat(float l)
{
- union {byte b[4]; float f;} in, out;
-
- in.f = l;
- out.b[0] = in.b[3];
- out.b[1] = in.b[2];
- out.b[2] = in.b[1];
- out.b[3] = in.b[0];
-
- return out.f;
+ union { byte b[4]; float f; } in, out;
+
+ in.f = l;
+ out.b[0] = in.b[3];
+ out.b[1] = in.b[2];
+ out.b[2] = in.b[1];
+ out.b[3] = in.b[0];
+
+ return out.f;
}
-float LittleFloat (float l)
+float LittleFloat(float l)
{
- return l;
+ return l;
}
-
#endif
-
//=======================================================
-
// FIXME: byte swap?
// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
@@ -888,53 +850,53 @@ float LittleFloat (float l)
static unsigned short crctable[256] =
{
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
-void CRC_Init(unsigned short *crcvalue)
+void CRC_Init(unsigned short* crcvalue)
{
- *crcvalue = CRC_INIT_VALUE;
+ *crcvalue = CRC_INIT_VALUE;
}
-void CRC_ProcessByte(unsigned short *crcvalue, byte data)
+void CRC_ProcessByte(unsigned short* crcvalue, byte data)
{
- *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+ *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
}
unsigned short CRC_Value(unsigned short crcvalue)
{
- return crcvalue ^ CRC_XOR_VALUE;
+ return crcvalue ^ CRC_XOR_VALUE;
}
//=============================================================================
@@ -943,22 +905,21 @@ unsigned short CRC_Value(unsigned short crcvalue)
CreatePath
============
*/
-void CreatePath (char *path)
+void CreatePath(char* path)
{
- char *ofs, c;
-
- for (ofs = path+1 ; *ofs ; ofs++)
- {
- c = *ofs;
- if (c == '/' || c == '\\')
- { // create the directory
- *ofs = 0;
- Q_mkdir (path);
- *ofs = c;
- }
- }
-}
+ char* ofs, c;
+ for (ofs = path + 1; *ofs; ofs++)
+ {
+ c = *ofs;
+ if (c == '/' || c == '\\')
+ { // create the directory
+ *ofs = 0;
+ Q_mkdir(path);
+ *ofs = c;
+ }
+ }
+}
/*
============
@@ -967,18 +928,17 @@ QCopyFile
Used to archive source files
============
*/
-void QCopyFile (char *from, char *to)
+void QCopyFile(char* from, char* to)
{
- void *buffer;
- int length;
+ void* buffer;
+ int length;
- length = LoadFile (from, &buffer);
- CreatePath (to);
- SaveFile (to, buffer, length);
- free (buffer);
+ length = LoadFile(from, &buffer);
+ CreatePath(to);
+ SaveFile(to, buffer, length);
+ free(buffer);
}
-
/*
============
ListPak
@@ -989,44 +949,41 @@ ListPak
void ListPak(char* pakname)
{
- FILE* f = SafeOpenRead(pakname);
- packheader_t head;
- packfile_t* pdir;
- long i=0,imax=0;
- long totlen=0;
+ FILE* f = SafeOpenRead(pakname);
+ packheader_t head;
+ packfile_t* pdir;
+ long i = 0, imax = 0;
+ long totlen = 0;
- SafeRead(f,&head,sizeof(packheader_t));
- pdir = (packfile_t *)malloc(head.dirlen);
+ SafeRead(f, &head, sizeof(packheader_t));
+ pdir = (packfile_t*)malloc(head.dirlen);
- fseek(f,head.dirofs,SEEK_SET);
- SafeRead(f,pdir,head.dirlen);
-
- fseek(f,0,SEEK_END);
- totlen=ftell(f);
+ fseek(f, head.dirofs, SEEK_SET);
+ SafeRead(f, pdir, head.dirlen);
- fclose(f);
+ fseek(f, 0, SEEK_END);
+ totlen = ftell(f);
- imax=head.dirlen/sizeof(packfile_t);
+ fclose(f);
- for(i;iidentifier)
-
// set these before calling CheckParm
extern int myargc;
-extern char **myargv;
+extern char** myargv;
-char *strupr (char *in);
-char *strlower (char *in);
-int Q_strncasecmp (char *s1, char *s2, int n);
-int Q_strcasecmp (char *s1, char *s2);
-void Q_getwd (char *out);
+char* strupr(char* in);
+char* strlower(char* in);
+int Q_strncasecmp(char* s1, char* s2, int n);
+int Q_strcasecmp(char* s1, char* s2);
+void Q_getwd(char* out);
-int filelength (FILE *f);
-int FileTime (char *path);
+int filelength(FILE* f);
+int FileTime(char* path);
-void Q_mkdir (char *path);
+void Q_mkdir(char* path);
extern char qdir[1024];
extern char gamedir[1024];
-void SetQdirFromPath (char *path);
-char *ExpandArg (char *path); // from cmd line
-char *ExpandPath (char *path); // from scripts
-char *ExpandPathAndArchive (char *path);
-
+void SetQdirFromPath(char* path);
+char* ExpandArg(char* path); // from cmd line
+char* ExpandPath(char* path); // from scripts
+char* ExpandPathAndArchive(char* path);
-double I_FloatTime (void);
+double I_FloatTime(void);
-void Error (char *error, ...);
-int CheckParm (char *check);
+void Error(char* error, ...);
+int CheckParm(char* check);
-FILE *SafeOpenWrite (char *filename);
-FILE *SafeOpenRead (char *filename);
-void SafeRead (FILE *f, void *buffer, int count);
-void SafeWrite (FILE *f, void *buffer, int count);
+FILE* SafeOpenWrite(char* filename);
+FILE* SafeOpenRead(char* filename);
+void SafeRead(FILE* f, void* buffer, int count);
+void SafeWrite(FILE* f, void* buffer, int count);
-int LoadFile (char *filename, void **bufferptr);
-void SaveFile (char *filename, void *buffer, int count);
+int LoadFile(char* filename, void** bufferptr);
+void SaveFile(char* filename, void* buffer, int count);
-void DefaultExtension (char *path, char *extension);
-void DefaultPath (char *path, char *basepath);
-void StripFilename (char *path);
-void StripExtension (char *path);
+void DefaultExtension(char* path, char* extension);
+void DefaultPath(char* path, char* basepath);
+void StripFilename(char* path);
+void StripExtension(char* path);
-void ExtractFilePath (char *path, char *dest);
-void ExtractFileBase (char *path, char *dest);
-void ExtractFileExtension (char *path, char *dest);
+void ExtractFilePath(char* path, char* dest);
+void ExtractFileBase(char* path, char* dest);
+void ExtractFileExtension(char* path, char* dest);
-int ParseNum (char *str);
+int ParseNum(char* str);
-short BigShort (short l);
-short LittleShort (short l);
-int BigLong (int l);
-int LittleLong (int l);
-float BigFloat (float l);
-float LittleFloat (float l);
+short BigShort(short l);
+short LittleShort(short l);
+int BigLong(int l);
+int LittleLong(int l);
+float BigFloat(float l);
+float LittleFloat(float l);
long flen(FILE* f);
-
-
-char *COM_Parse (char *data);
+char* COM_Parse(char* data);
extern char com_token[1024];
extern qboolean com_eof;
-char *copystring(char *s);
-
+char* copystring(char* s);
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
+void CRC_Init(unsigned short* crcvalue);
+void CRC_ProcessByte(unsigned short* crcvalue, byte data);
unsigned short CRC_Value(unsigned short crcvalue);
-void CreatePath (char *path);
-void QCopyFile (char *from, char *to);
+void CreatePath(char* path);
+void QCopyFile(char* from, char* to);
extern qboolean archive;
extern char archivedir[1024];
-
extern qboolean verbose;
-void qprintf (char *format, ...);
-
+void qprintf(char* format, ...);
typedef struct
{
- char name[56];
- int filepos, filelen;
+ char name[56];
+ int filepos, filelen;
} packfile_t;
typedef struct
{
- char id[4];
- int dirofs;
- int dirlen;
+ char id[4];
+ int dirofs;
+ int dirlen;
} packheader_t;
-
void ListPak(char* pakname);
#endif // CMDLIB
-
diff --git a/Bsp2Rbn/dummy.cpp b/Bsp2Rbn/dummy.cpp
index 349ed67..c89480d 100644
--- a/Bsp2Rbn/dummy.cpp
+++ b/Bsp2Rbn/dummy.cpp
@@ -13,7 +13,6 @@
#include
#include
-
#include "../bot.h"
#include "../game.h"
#include "../bot_weapons.h"
@@ -26,7 +25,7 @@
enginefuncs_t g_engfuncs;
globalvars_t pGlobals;
-globalvars_t *gpGlobals = &pGlobals;
+globalvars_t* gpGlobals = &pGlobals;
char g_argv[1024];
cBot bots[32];
@@ -39,96 +38,92 @@ cGame Game;
cNodeMachine NodeMachine;
cChatEngine ChatEngine;
-void FakeClientCommand (edict_t * pBot, char *arg1, char *arg2, char *arg3)
-{
- fprintf(stderr,"FakeClientCommand is called!\n") ;
- exit(1) ;
+void FakeClientCommand(edict_t* pBot, char* arg1, char* arg2, char* arg3)
+{
+ fprintf(stderr, "FakeClientCommand is called!\n");
+ exit(1);
}
-
// From game.cpp
// Debug message
-void REALBOT_PRINT (cBot * pBot, const char *Function, const char *msg)
+void REALBOT_PRINT(cBot* pBot, const char* Function, const char* msg)
{
- // Message format:
- // Function name - [BOT NAME, BOT TEAM]: Message
- char team[9];
- char name[32];
-
- memset(team, 0, sizeof(team)); // clear
- memset(name, 0, sizeof(name)); // clear
-
- strcpy(team, "TERROR"); // t
- strcpy(name, "FUNCTION");
-
- if (pBot)
- {
- memset(name, 0, sizeof(name)); // clear
- strcpy(name, pBot->name); // copy name
-
- if (pBot->iTeam == 2) strcpy(team, "COUNTER");
- }
- else
- {
- strcpy(team, "NONE");
- }
-
- printf ("RBPRINT->[%s '%s']-[Team %s] : %s\n", name, Function, team, msg);
-
- char msgForFile[512];
- memset(msgForFile, 0, sizeof(msgForFile)); // clear
- sprintf (msgForFile, "RBPRINT->[%s '%s']-[Team %s] : %s\n", name, Function, team, msg);
- rblog(msgForFile);
+ // Message format:
+ // Function name - [BOT NAME, BOT TEAM]: Message
+ char team[9];
+ char name[32];
+
+ memset(team, 0, sizeof(team)); // clear
+ memset(name, 0, sizeof(name)); // clear
+
+ strcpy(team, "TERROR"); // t
+ strcpy(name, "FUNCTION");
+
+ if (pBot)
+ {
+ memset(name, 0, sizeof(name)); // clear
+ strcpy(name, pBot->name); // copy name
+
+ if (pBot->iTeam == 2) strcpy(team, "COUNTER");
+ }
+ else
+ {
+ strcpy(team, "NONE");
+ }
+
+ printf("RBPRINT->[%s '%s']-[Team %s] : %s\n", name, Function, team, msg);
+
+ char msgForFile[512];
+ memset(msgForFile, 0, sizeof(msgForFile)); // clear
+ sprintf(msgForFile, "RBPRINT->[%s '%s']-[Team %s] : %s\n", name, Function, team, msg);
+ rblog(msgForFile);
}
-
// from ChatENgine.cpp
void cChatEngine::set_sentence(char csender[30], char csentence[128])
{
- fprintf(stderr,"cChatEngine::set_sentence is called!\n") ;
- exit(1) ;
+ fprintf(stderr, "cChatEngine::set_sentence is called!\n");
+ exit(1);
}
// From bot.cpp
// Can see Edict?
-bool cBot::canSeeEntity (edict_t * pEntity)
+bool cBot::canSeeEntity(edict_t* pEntity) const
{
- TraceResult tr;
- Vector start = pEdict->v.origin + pEdict->v.view_ofs;
- Vector vDest = pEntity->v.origin;
+ TraceResult tr;
+ Vector start = pEdict->v.origin + pEdict->v.view_ofs;
+ Vector vDest = pEntity->v.origin;
- // trace a line from bot's eyes to destination...
- UTIL_TraceLine (start, vDest, ignore_monsters, pEdict->v.pContainingEntity, &tr);
+ // trace a line from bot's eyes to destination...
+ UTIL_TraceLine(start, vDest, ignore_monsters, pEdict->v.pContainingEntity, &tr);
- if (tr.flFraction < 1.0)
- {
- // when the 'hit entity' is the same as pEntity, then its ok
- if (tr.pHit == pEntity)
- return true; // it is visible
+ if (tr.flFraction < 1.0)
+ {
+ // when the 'hit entity' is the same as pEntity, then its ok
+ if (tr.pHit == pEntity)
+ return true; // it is visible
- return false;
- }
+ return false;
+ }
- return true;
+ return true;
}
-bool cBot::Defuse ()
+bool cBot::Defuse()
{
- fprintf(stderr,"cBot::Defuse is called!\n") ;
- exit(1) ;
+ fprintf(stderr, "cBot::Defuse is called!\n");
+ exit(1);
}
-
// From IniParser.cpp
// Parse IAD file:
// Important Area Definition file
void INI_PARSE_IAD()
{
- fprintf(stderr,"INI_PARSE_IAD is called!\n") ;
- exit(1) ;
-}
-
+ fprintf(stderr, "INI_PARSE_IAD is called!\n");
+ exit(1);
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/entity.cpp b/Bsp2Rbn/entity.cpp
index 33996de..f8edaab 100644
--- a/Bsp2Rbn/entity.cpp
+++ b/Bsp2Rbn/entity.cpp
@@ -1,164 +1,159 @@
-//
-// BSP_tool - botman's Half-Life BSP utilities
-//
-// (http://planethalflife.com/botman/)
-//
-// entity.cpp
-//
-// Copyright (C) 2001 - Jeffrey "botman" Broome
-//
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-//
-// See the GNU General Public License for more details at:
-// http://www.gnu.org/copyleft/gpl.html
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#include
-
-#include
-#include
-
-// chierie de /home/evyncke/cstrike/Realbot/HLSDK/multiplayer/cl_dll/util_vector.h definissant vec3_t comme Vector
-
-
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "bspfile.h"
-#include "entity.h"
-
-vec3_t spawn_point;
-float spawn_point_yaw;
-
-epair_t *pEpair = NULL;
-
-int Botman_num_entvars = 0;
-Botman_entvars_t Botman_entvars[MAX_MAP_ENTITIES];
-
-
-void LoadEntVars(void)
-{
- int ent_index = 0;
- char *value;
-
- while (ent_index < num_entities)
- {
- value = ValueForKey(&entities[ent_index], "classname");
-
- if (value[0])
- {
- strcpy(Botman_entvars[Botman_num_entvars].classname, value);
-
- // initialize the default entvars fields...
- Botman_entvars[Botman_num_entvars].origin[0] = 0.0f;
- Botman_entvars[Botman_num_entvars].origin[1] = 0.0f;
- Botman_entvars[Botman_num_entvars].origin[2] = 0.0f;
-
- Botman_entvars[Botman_num_entvars].angles[0] = 0.0f;
- Botman_entvars[Botman_num_entvars].angles[1] = 0.0f;
- Botman_entvars[Botman_num_entvars].angles[2] = 0.0f;
-
- Botman_entvars[Botman_num_entvars].rendermode = 0;
- Botman_entvars[Botman_num_entvars].renderamt = 1.0f;
- Botman_entvars[Botman_num_entvars].rendercolor[0] = 1.0f;
- Botman_entvars[Botman_num_entvars].rendercolor[1] = 1.0f;
- Botman_entvars[Botman_num_entvars].rendercolor[2] = 1.0f;
- Botman_entvars[Botman_num_entvars].renderfx = 0;
-
- Botman_entvars[Botman_num_entvars].brush_model_index = 0;
-
- Botman_entvars[Botman_num_entvars].studio_model = NULL;
-
- value = ValueForKey(&entities[ent_index], "origin");
- if (value[0])
- {
- sscanf(value, "%f %f %f", &Botman_entvars[Botman_num_entvars].origin[0],
- &Botman_entvars[Botman_num_entvars].origin[1],
- &Botman_entvars[Botman_num_entvars].origin[2]);
- }
-
- value = ValueForKey(&entities[ent_index], "angle");
- if (value[0])
- {
- // set the yaw angle...
- sscanf(value, "%f", &Botman_entvars[Botman_num_entvars].angles[1]);
- }
-
- value = ValueForKey(&entities[ent_index], "renderamt");
- if (value[0])
- {
- int n_renderamt;
-
- sscanf(value, "%d", &n_renderamt);
- Botman_entvars[Botman_num_entvars].renderamt = n_renderamt / 255.0f;
- }
-
- value = ValueForKey(&entities[ent_index], "rendercolor");
- if (value[0])
- {
- int n_color_r, n_color_b, n_color_g;
-
- sscanf(value, "%d %d %d", &n_color_r, &n_color_g, &n_color_b);
- Botman_entvars[Botman_num_entvars].rendercolor[0] = n_color_r / 255.0f;
- Botman_entvars[Botman_num_entvars].rendercolor[1] = n_color_g / 255.0f;
- Botman_entvars[Botman_num_entvars].rendercolor[2] = n_color_b / 255.0f;
- }
-
- value = ValueForKey(&entities[ent_index], "model");
- if (value[0])
- {
- if (sscanf(value, "*%d", &Botman_entvars[Botman_num_entvars].brush_model_index) == 1)
- {
- dmodel_t *model;
-
- // calculate the origin for this brush model...
- model = &dmodels[Botman_entvars[Botman_num_entvars].brush_model_index];
-
- Botman_entvars[Botman_num_entvars].origin[0] = (model->mins[0] + model->maxs[0]) / 2.0f;
- Botman_entvars[Botman_num_entvars].origin[1] = (model->mins[1] + model->maxs[1]) / 2.0f;
- Botman_entvars[Botman_num_entvars].origin[2] = (model->mins[2] + model->maxs[2]) / 2.0f;
- }
- }
-
- if ((strcmp(Botman_entvars[Botman_num_entvars].classname, "func_button") == 0) ||
- (strcmp(Botman_entvars[Botman_num_entvars].classname, "func_door") == 0))
- {
- // always render func_button and func_door entities...
- Botman_entvars[Botman_num_entvars].renderamt = 255;
- }
-
- Botman_num_entvars++;
- }
-
- ent_index++;
- }
-}
-
-
-void InitSpawnPoint(void)
-{
- int ent_index;
- int count = 0;
- char *value;
- int pick, loop;
-
- spawn_point[0] = 0.0;
- spawn_point[1] = 0.0;
- spawn_point[2] = 0.0;
- spawn_point_yaw = 0.0;
-
-// if (config.spawnpoint[0] == 0)
- return; // no spawn points configured, just return
-
-}
+//
+// BSP_tool - botman's Half-Life BSP utilities
+//
+// (http://planethalflife.com/botman/)
+//
+// entity.cpp
+//
+// Copyright (C) 2001 - Jeffrey "botman" Broome
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//
+// See the GNU General Public License for more details at:
+// http://www.gnu.org/copyleft/gpl.html
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include
+
+#include
+#include
+
+// chierie de /home/evyncke/cstrike/Realbot/HLSDK/multiplayer/cl_dll/util_vector.h definissant vec3_t comme Vector
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "bspfile.h"
+#include "entity.h"
+
+vec3_t spawn_point;
+float spawn_point_yaw;
+
+epair_t* pEpair = NULL;
+
+int Botman_num_entvars = 0;
+Botman_entvars_t Botman_entvars[MAX_MAP_ENTITIES];
+
+void LoadEntVars(void)
+{
+ int ent_index = 0;
+ char* value;
+
+ while (ent_index < num_entities)
+ {
+ value = ValueForKey(&entities[ent_index], "classname");
+
+ if (value[0])
+ {
+ strcpy(Botman_entvars[Botman_num_entvars].classname, value);
+
+ // initialize the default entvars fields...
+ Botman_entvars[Botman_num_entvars].origin[0] = 0.0f;
+ Botman_entvars[Botman_num_entvars].origin[1] = 0.0f;
+ Botman_entvars[Botman_num_entvars].origin[2] = 0.0f;
+
+ Botman_entvars[Botman_num_entvars].angles[0] = 0.0f;
+ Botman_entvars[Botman_num_entvars].angles[1] = 0.0f;
+ Botman_entvars[Botman_num_entvars].angles[2] = 0.0f;
+
+ Botman_entvars[Botman_num_entvars].rendermode = 0;
+ Botman_entvars[Botman_num_entvars].renderamt = 1.0f;
+ Botman_entvars[Botman_num_entvars].rendercolor[0] = 1.0f;
+ Botman_entvars[Botman_num_entvars].rendercolor[1] = 1.0f;
+ Botman_entvars[Botman_num_entvars].rendercolor[2] = 1.0f;
+ Botman_entvars[Botman_num_entvars].renderfx = 0;
+
+ Botman_entvars[Botman_num_entvars].brush_model_index = 0;
+
+ Botman_entvars[Botman_num_entvars].studio_model = NULL;
+
+ value = ValueForKey(&entities[ent_index], "origin");
+ if (value[0])
+ {
+ sscanf(value, "%f %f %f", &Botman_entvars[Botman_num_entvars].origin[0],
+ &Botman_entvars[Botman_num_entvars].origin[1],
+ &Botman_entvars[Botman_num_entvars].origin[2]);
+ }
+
+ value = ValueForKey(&entities[ent_index], "angle");
+ if (value[0])
+ {
+ // set the yaw angle...
+ sscanf(value, "%f", &Botman_entvars[Botman_num_entvars].angles[1]);
+ }
+
+ value = ValueForKey(&entities[ent_index], "renderamt");
+ if (value[0])
+ {
+ int n_renderamt;
+
+ sscanf(value, "%d", &n_renderamt);
+ Botman_entvars[Botman_num_entvars].renderamt = n_renderamt / 255.0f;
+ }
+
+ value = ValueForKey(&entities[ent_index], "rendercolor");
+ if (value[0])
+ {
+ int n_color_r, n_color_b, n_color_g;
+
+ sscanf(value, "%d %d %d", &n_color_r, &n_color_g, &n_color_b);
+ Botman_entvars[Botman_num_entvars].rendercolor[0] = n_color_r / 255.0f;
+ Botman_entvars[Botman_num_entvars].rendercolor[1] = n_color_g / 255.0f;
+ Botman_entvars[Botman_num_entvars].rendercolor[2] = n_color_b / 255.0f;
+ }
+
+ value = ValueForKey(&entities[ent_index], "model");
+ if (value[0])
+ {
+ if (sscanf(value, "*%d", &Botman_entvars[Botman_num_entvars].brush_model_index) == 1)
+ {
+ dmodel_t* model;
+
+ // calculate the origin for this brush model...
+ model = &dmodels[Botman_entvars[Botman_num_entvars].brush_model_index];
+
+ Botman_entvars[Botman_num_entvars].origin[0] = (model->mins[0] + model->maxs[0]) / 2.0f;
+ Botman_entvars[Botman_num_entvars].origin[1] = (model->mins[1] + model->maxs[1]) / 2.0f;
+ Botman_entvars[Botman_num_entvars].origin[2] = (model->mins[2] + model->maxs[2]) / 2.0f;
+ }
+ }
+
+ if ((strcmp(Botman_entvars[Botman_num_entvars].classname, "func_button") == 0) ||
+ (strcmp(Botman_entvars[Botman_num_entvars].classname, "func_door") == 0))
+ {
+ // always render func_button and func_door entities...
+ Botman_entvars[Botman_num_entvars].renderamt = 255;
+ }
+
+ Botman_num_entvars++;
+ }
+
+ ent_index++;
+ }
+}
+
+void InitSpawnPoint(void)
+{
+ int ent_index;
+ int count = 0;
+ char* value;
+ int pick, loop;
+
+ spawn_point[0] = 0.0;
+ spawn_point[1] = 0.0;
+ spawn_point[2] = 0.0;
+ spawn_point_yaw = 0.0;
+
+ // if (config.spawnpoint[0] == 0)
+ return; // no spawn points configured, just return
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/entity.h b/Bsp2Rbn/entity.h
index d3b5828..52178ad 100644
--- a/Bsp2Rbn/entity.h
+++ b/Bsp2Rbn/entity.h
@@ -15,7 +15,7 @@
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License for more details at:
// http://www.gnu.org/copyleft/gpl.html
@@ -33,17 +33,17 @@
typedef struct Botman_entvars_s
{
- char classname[64];
- vec3_t origin;
- vec3_t angles;
+ char classname[64];
+ vec3_t origin;
+ vec3_t angles;
- int rendermode;
- float renderamt;
- vec3_t rendercolor;
- int renderfx;
+ int rendermode;
+ float renderamt;
+ vec3_t rendercolor;
+ int renderfx;
- int brush_model_index;
- StudioModel *studio_model;
+ int brush_model_index;
+ StudioModel* studio_model;
} Botman_entvars_t;
extern int Botman_num_entvars;
@@ -58,4 +58,3 @@ void LoadEntVars(void);
void InitSpawnPoint(void);
#endif
-
diff --git a/Bsp2Rbn/mathlib.cpp b/Bsp2Rbn/mathlib.cpp
index 61f9815..31118ce 100644
--- a/Bsp2Rbn/mathlib.cpp
+++ b/Bsp2Rbn/mathlib.cpp
@@ -1,9 +1,9 @@
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
-*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+*
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
****/
@@ -19,143 +19,140 @@
// chierie de /home/evyncke/cstrike/Realbot/HLSDK/multiplayer/cl_dll/util_vector.h definissant vec3_t comme Vector
-
#include "cmdlib.h"
#include "mathlib.h"
-vec3_t vec3_origin = Vector(0,0,0);
-
+vec3_t vec3_origin = Vector(0, 0, 0);
double Vector2DLength(vec3_t v)
{
- int i;
- double length;
+ int i;
+ double length;
- length = 0;
- for (i=0 ; i< 2 ; i++) // ignore the Z axis
- length += v[i]*v[i];
- length = (float)sqrt(length); // FIXME
+ length = 0;
+ for (i = 0; i < 2; i++) // ignore the Z axis
+ length += v[i] * v[i];
+ length = (float)sqrt(length); // FIXME
- return length;
+ return length;
}
double VectorLength(vec3_t v)
{
int i;
double length;
-
+
length = 0;
- for (i=0 ; i< 3 ; i++)
- length += v[i]*v[i];
- length = sqrt (length); // FIXME
+ for (i = 0; i < 3; i++)
+ length += v[i] * v[i];
+ length = sqrt(length); // FIXME
return length;
}
-
-int VectorCompare (vec3_t v1, vec3_t v2)
+int VectorCompare(vec3_t v1, vec3_t v2)
{
int i;
-
- for (i=0 ; i<3 ; i++)
- if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
+
+ for (i = 0; i < 3; i++)
+ if (fabs(v1[i] - v2[i]) > EQUAL_EPSILON)
return false;
-
+
return true;
}
-vec_t Q_rint (vec_t in)
+vec_t Q_rint(vec_t in)
{
- return floor (in + 0.5);
+ return floor(in + 0.5);
}
-void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
+void VectorMA(vec3_t va, double scale, vec3_t vb, vec3_t vc)
{
- vc[0] = va[0] + scale*vb[0];
- vc[1] = va[1] + scale*vb[1];
- vc[2] = va[2] + scale*vb[2];
+ vc[0] = va[0] + scale * vb[0];
+ vc[1] = va[1] + scale * vb[1];
+ vc[2] = va[2] + scale * vb[2];
}
-void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
+void CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross)
{
- cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
- cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
- cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
+ cross[0] = v1[1] * v2[2] - v1[2] * v2[1];
+ cross[1] = v1[2] * v2[0] - v1[0] * v2[2];
+ cross[2] = v1[0] * v2[1] - v1[1] * v2[0];
}
-vec_t _DotProduct (vec3_t v1, vec3_t v2)
+vec_t _DotProduct(vec3_t v1, vec3_t v2)
{
- return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+ return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
-void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
+void _VectorSubtract(vec3_t va, vec3_t vb, vec3_t out)
{
- out[0] = va[0]-vb[0];
- out[1] = va[1]-vb[1];
- out[2] = va[2]-vb[2];
+ out[0] = va[0] - vb[0];
+ out[1] = va[1] - vb[1];
+ out[2] = va[2] - vb[2];
}
-void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
+void _VectorAdd(vec3_t va, vec3_t vb, vec3_t out)
{
- out[0] = va[0]+vb[0];
- out[1] = va[1]+vb[1];
- out[2] = va[2]+vb[2];
+ out[0] = va[0] + vb[0];
+ out[1] = va[1] + vb[1];
+ out[2] = va[2] + vb[2];
}
-void _VectorCopy (vec3_t in, vec3_t out)
+void _VectorCopy(vec3_t in, vec3_t out)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
}
-void _VectorScale (vec3_t v, vec_t scale, vec3_t out)
+void _VectorScale(vec3_t v, vec_t scale, vec3_t out)
{
out[0] = v[0] * scale;
out[1] = v[1] * scale;
out[2] = v[2] * scale;
}
-vec_t VectorNormalize (vec3_t v)
+vec_t VectorNormalize(vec3_t v)
{
int i;
double length;
-if ( fabs(v[1] - 0.000215956) < 0.0001)
-i=1;
+ if (fabs(v[1] - 0.000215956) < 0.0001)
+ i = 1;
length = 0;
- for (i=0 ; i< 3 ; i++)
- length += v[i]*v[i];
- length = sqrt (length);
+ for (i = 0; i < 3; i++)
+ length += v[i] * v[i];
+ length = sqrt(length);
if (length == 0)
return 0;
-
- for (i=0 ; i< 3 ; i++)
- v[i] /= length;
+
+ for (i = 0; i < 3; i++)
+ v[i] /= length;
return length;
}
-void VectorInverse (vec3_t v)
+void VectorInverse(vec3_t v)
{
v[0] = -v[0];
v[1] = -v[1];
v[2] = -v[2];
}
-void ClearBounds (vec3_t mins, vec3_t maxs)
+void ClearBounds(vec3_t mins, vec3_t maxs)
{
mins[0] = mins[1] = mins[2] = 99999;
maxs[0] = maxs[1] = maxs[2] = -99999;
}
-void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
+void AddPointToBounds(vec3_t v, vec3_t mins, vec3_t maxs)
{
int i;
vec_t val;
- for (i=0 ; i<3 ; i++)
+ for (i = 0; i < 3; i++)
{
val = v[i];
if (val < mins[i])
@@ -165,158 +162,151 @@ void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
}
}
-void AngleMatrix (const vec3_t angles, float (*matrix)[4] )
+void AngleMatrix(const vec3_t angles, float(*matrix)[4])
{
float angle;
float sr, sp, sy, cr, cp, cy;
-
- angle = angles[2] * (Q_PI*2 / 360);
+
+ angle = angles[2] * (Q_PI * 2 / 360);
sy = sin(angle);
cy = cos(angle);
- angle = angles[1] * (Q_PI*2 / 360);
+ angle = angles[1] * (Q_PI * 2 / 360);
sp = sin(angle);
cp = cos(angle);
- angle = angles[0] * (Q_PI*2 / 360);
+ angle = angles[0] * (Q_PI * 2 / 360);
sr = sin(angle);
cr = cos(angle);
// matrix = (Z * Y) * X
- matrix[0][0] = cp*cy;
- matrix[1][0] = cp*sy;
+ matrix[0][0] = cp * cy;
+ matrix[1][0] = cp * sy;
matrix[2][0] = -sp;
- matrix[0][1] = sr*sp*cy+cr*-sy;
- matrix[1][1] = sr*sp*sy+cr*cy;
- matrix[2][1] = sr*cp;
- matrix[0][2] = (cr*sp*cy+-sr*-sy);
- matrix[1][2] = (cr*sp*sy+-sr*cy);
- matrix[2][2] = cr*cp;
+ matrix[0][1] = sr * sp * cy + cr * -sy;
+ matrix[1][1] = sr * sp * sy + cr * cy;
+ matrix[2][1] = sr * cp;
+ matrix[0][2] = (cr * sp * cy + -sr * -sy);
+ matrix[1][2] = (cr * sp * sy + -sr * cy);
+ matrix[2][2] = cr * cp;
matrix[0][3] = 0.0;
matrix[1][3] = 0.0;
matrix[2][3] = 0.0;
}
-void AngleIMatrix (const vec3_t angles, float matrix[3][4] )
+void AngleIMatrix(const vec3_t angles, float matrix[3][4])
{
float angle;
float sr, sp, sy, cr, cp, cy;
-
- angle = angles[2] * (Q_PI*2 / 360);
+
+ angle = angles[2] * (Q_PI * 2 / 360);
sy = sin(angle);
cy = cos(angle);
- angle = angles[1] * (Q_PI*2 / 360);
+ angle = angles[1] * (Q_PI * 2 / 360);
sp = sin(angle);
cp = cos(angle);
- angle = angles[0] * (Q_PI*2 / 360);
+ angle = angles[0] * (Q_PI * 2 / 360);
sr = sin(angle);
cr = cos(angle);
// matrix = (Z * Y) * X
- matrix[0][0] = cp*cy;
- matrix[0][1] = cp*sy;
+ matrix[0][0] = cp * cy;
+ matrix[0][1] = cp * sy;
matrix[0][2] = -sp;
- matrix[1][0] = sr*sp*cy+cr*-sy;
- matrix[1][1] = sr*sp*sy+cr*cy;
- matrix[1][2] = sr*cp;
- matrix[2][0] = (cr*sp*cy+-sr*-sy);
- matrix[2][1] = (cr*sp*sy+-sr*cy);
- matrix[2][2] = cr*cp;
+ matrix[1][0] = sr * sp * cy + cr * -sy;
+ matrix[1][1] = sr * sp * sy + cr * cy;
+ matrix[1][2] = sr * cp;
+ matrix[2][0] = (cr * sp * cy + -sr * -sy);
+ matrix[2][1] = (cr * sp * sy + -sr * cy);
+ matrix[2][2] = cr * cp;
matrix[0][3] = 0.0;
matrix[1][3] = 0.0;
matrix[2][3] = 0.0;
}
-void R_ConcatTransforms (const float in1[3][4], const float in2[3][4], float out[3][4])
+void R_ConcatTransforms(const float in1[3][4], const float in2[3][4], float out[3][4])
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
- in1[0][2] * in2[2][0];
+ in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
- in1[0][2] * in2[2][1];
+ in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
- in1[0][2] * in2[2][2];
+ in1[0][2] * in2[2][2];
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
- in1[0][2] * in2[2][3] + in1[0][3];
+ in1[0][2] * in2[2][3] + in1[0][3];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
- in1[1][2] * in2[2][0];
+ in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
- in1[1][2] * in2[2][1];
+ in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
- in1[1][2] * in2[2][2];
+ in1[1][2] * in2[2][2];
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
- in1[1][2] * in2[2][3] + in1[1][3];
+ in1[1][2] * in2[2][3] + in1[1][3];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
- in1[2][2] * in2[2][0];
+ in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
- in1[2][2] * in2[2][1];
+ in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
- in1[2][2] * in2[2][2];
+ in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
- in1[2][2] * in2[2][3] + in1[2][3];
+ in1[2][2] * in2[2][3] + in1[2][3];
}
-
-
-void VectorRotate (const vec3_t in1, const float in2[3][4], vec3_t out)
+void VectorRotate(const vec3_t in1, const float in2[3][4], vec3_t out)
{
out[0] = DotProduct(in1, in2[0]);
out[1] = DotProduct(in1, in2[1]);
out[2] = DotProduct(in1, in2[2]);
}
-
// rotate by the inverse of the matrix
-void VectorIRotate (const vec3_t in1, const float in2[3][4], vec3_t out)
+void VectorIRotate(const vec3_t in1, const float in2[3][4], vec3_t out)
{
- out[0] = in1[0]*in2[0][0] + in1[1]*in2[1][0] + in1[2]*in2[2][0];
- out[1] = in1[0]*in2[0][1] + in1[1]*in2[1][1] + in1[2]*in2[2][1];
- out[2] = in1[0]*in2[0][2] + in1[1]*in2[1][2] + in1[2]*in2[2][2];
+ out[0] = in1[0] * in2[0][0] + in1[1] * in2[1][0] + in1[2] * in2[2][0];
+ out[1] = in1[0] * in2[0][1] + in1[1] * in2[1][1] + in1[2] * in2[2][1];
+ out[2] = in1[0] * in2[0][2] + in1[1] * in2[1][2] + in1[2] * in2[2][2];
}
-
-void VectorTransform (const vec3_t in1, const float in2[3][4], vec3_t out)
+void VectorTransform(const vec3_t in1, const float in2[3][4], vec3_t out)
{
out[0] = DotProduct(in1, in2[0]) + in2[0][3];
- out[1] = DotProduct(in1, in2[1]) + in2[1][3];
- out[2] = DotProduct(in1, in2[2]) + in2[2][3];
+ out[1] = DotProduct(in1, in2[1]) + in2[1][3];
+ out[2] = DotProduct(in1, in2[2]) + in2[2][3];
}
-
// WARNING!!! the "vector" parameter should be NORMALIZED!!!
float DistanceToIntersection(const vec3_t origin, const vec3_t vector,
- const vec3_t plane_origin, const vec3_t plane_normal)
+ const vec3_t plane_origin, const vec3_t plane_normal)
{
- float d = -(DotProduct(plane_normal, plane_origin));
-
- float numerator = DotProduct(plane_normal, origin) + d;
- float denominator = DotProduct(plane_normal, vector);
-
- if (fabs(denominator) < 0.00001)
- return (-1.0f); // normal is orthogonal to vector, no intersection
-
- return -(numerator/denominator);
-}
+ float d = -(DotProduct(plane_normal, plane_origin));
+
+ float numerator = DotProduct(plane_normal, origin) + d;
+ float denominator = DotProduct(plane_normal, vector);
+ if (fabs(denominator) < 0.00001)
+ return (-1.0f); // normal is orthogonal to vector, no intersection
+
+ return -(numerator / denominator);
+}
// return TRUE or FALSE if vector intersects a plane...
bool VectorIntersectPlane(const vec3_t origin, const vec3_t vector,
- const vec3_t plane_origin, const vec3_t plane_normal,
- vec3_t intersect_point)
+ const vec3_t plane_origin, const vec3_t plane_normal,
+ vec3_t intersect_point)
{
- float dist;
- vec3_t v_temp;
+ float dist;
+ vec3_t v_temp;
- dist = DistanceToIntersection(origin, vector, plane_origin, plane_normal);
+ dist = DistanceToIntersection(origin, vector, plane_origin, plane_normal);
- if (dist < 0)
- return FALSE;
+ if (dist < 0)
+ return FALSE;
- VectorScale(vector, dist, v_temp);
- VectorAdd(origin, v_temp, intersect_point);
+ VectorScale(vector, dist, v_temp);
+ VectorAdd(origin, v_temp, intersect_point);
- return TRUE;
+ return TRUE;
}
-
-void AngleQuaternion( const vec3_t angles, vec4_t quaternion )
+void AngleQuaternion(const vec3_t angles, vec4_t quaternion)
{
float angle;
float sr, sp, sy, cr, cp, cy;
@@ -332,15 +322,14 @@ void AngleQuaternion( const vec3_t angles, vec4_t quaternion )
sr = sin(angle);
cr = cos(angle);
- quaternion[0] = sr*cp*cy-cr*sp*sy; // X
- quaternion[1] = cr*sp*cy+sr*cp*sy; // Y
- quaternion[2] = cr*cp*sy-sr*sp*cy; // Z
- quaternion[3] = cr*cp*cy+sr*sp*sy; // W
+ quaternion[0] = sr * cp * cy - cr * sp * sy; // X
+ quaternion[1] = cr * sp * cy + sr * cp * sy; // Y
+ quaternion[2] = cr * cp * sy - sr * sp * cy; // Z
+ quaternion[3] = cr * cp * cy + sr * sp * sy; // W
}
-void QuaternionMatrix( const vec4_t quaternion, float (*matrix)[4] )
+void QuaternionMatrix(const vec4_t quaternion, float(*matrix)[4])
{
-
matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2];
matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2];
matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1];
@@ -354,7 +343,7 @@ void QuaternionMatrix( const vec4_t quaternion, float (*matrix)[4] )
matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1];
}
-void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt )
+void QuaternionSlerp(const vec4_t p, vec4_t q, float t, vec4_t qt)
{
int i;
float omega, cosom, sinom, sclp, sclq;
@@ -363,8 +352,8 @@ void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt )
float a = 0;
float b = 0;
for (i = 0; i < 4; i++) {
- a += (p[i]-q[i])*(p[i]-q[i]);
- b += (p[i]+q[i])*(p[i]+q[i]);
+ a += (p[i] - q[i]) * (p[i] - q[i]);
+ b += (p[i] + q[i]) * (p[i] + q[i]);
}
if (a > b) {
for (i = 0; i < 4; i++) {
@@ -372,14 +361,14 @@ void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt )
}
}
- cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
+ cosom = p[0] * q[0] + p[1] * q[1] + p[2] * q[2] + p[3] * q[3];
if ((1.0 + cosom) > 0.00000001) {
if ((1.0 - cosom) > 0.00000001) {
- omega = acos( cosom );
- sinom = sin( omega );
- sclp = sin( (1.0 - t)*omega) / sinom;
- sclq = sin( t*omega ) / sinom;
+ omega = acos(cosom);
+ sinom = sin(omega);
+ sclp = sin((1.0 - t) * omega) / sinom;
+ sclq = sin(t * omega) / sinom;
}
else {
sclp = 1.0 - t;
@@ -394,12 +383,10 @@ void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt )
qt[1] = p[0];
qt[2] = -p[3];
qt[3] = p[2];
- sclp = sin( (1.0 - t) * 0.5 * Q_PI);
- sclq = sin( t * 0.5 * Q_PI);
+ sclp = sin((1.0 - t) * 0.5 * Q_PI);
+ sclq = sin(t * 0.5 * Q_PI);
for (i = 0; i < 3; i++) {
qt[i] = sclp * p[i] + sclq * qt[i];
}
}
-}
-
-
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/mathlib.h b/Bsp2Rbn/mathlib.h
index 50f6ab6..b356b42 100644
--- a/Bsp2Rbn/mathlib.h
+++ b/Bsp2Rbn/mathlib.h
@@ -1,97 +1,95 @@
-/***
-*
-* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
-*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
-* All Rights Reserved.
-*
-****/
-
-#ifndef __MATHLIB__
-#define __MATHLIB__
-
-// mathlib.h
-
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef DOUBLEVEC_T
-typedef double vec_t;
-#else
-typedef float vec_t;
-#endif
-//typedef vec_t vec3_t[3]; // x,y,z
-typedef vec_t vec4_t[4]; // x,y,z,w
-
-#define SIDE_FRONT 0
-#define SIDE_ON 2
-#define SIDE_BACK 1
-#define SIDE_CROSS -2
-
-#define Q_PI 3.14159265358979323846
-
-extern vec3_t vec3_origin;
-
-// Use this definition globally
-#define ON_EPSILON 0.01
-#define EQUAL_EPSILON 0.001
-
-int VectorCompare (vec3_t v1, vec3_t v2);
-
-#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
-#define VectorFill(a,b) { (a)[0]=(b); (a)[1]=(b); (a)[2]=(b);}
-#define VectorAvg(a) ( ( (a)[0] + (a)[1] + (a)[2] ) / 3 )
-#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}
-#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}
-#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}
-#define VectorScale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];(c)[2]=(b)*(a)[2];}
-
-vec_t Q_rint (vec_t in);
-vec_t _DotProduct (vec3_t v1, vec3_t v2);
-void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
-void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
-void _VectorCopy (vec3_t in, vec3_t out);
-void _VectorScale (vec3_t v, vec_t scale, vec3_t out);
-
-double Vector2DLength(vec3_t v);
-double VectorLength(vec3_t v);
-
-void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc);
-
-void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
-vec_t VectorNormalize (vec3_t v);
-void VectorInverse (vec3_t v);
-
-void ClearBounds (vec3_t mins, vec3_t maxs);
-void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
-
-void AngleMatrix (const vec3_t angles, float matrix[3][4] );
-void AngleIMatrix (const vec3_t angles, float matrix[3][4] );
-void R_ConcatTransforms (const float in1[3][4], const float in2[3][4], float out[3][4]);
-
-void VectorIRotate (const vec3_t in1, const float in2[3][4], vec3_t out);
-void VectorRotate (const vec3_t in1, const float in2[3][4], vec3_t out);
-
-void VectorTransform (const vec3_t in1, const float in2[3][4], vec3_t out);
-
-float DistanceToIntersection(const vec3_t origin, const vec3_t vector,
- const vec3_t plane_origin, const vec3_t plane_normal);
-bool VectorIntersectPlane(const vec3_t origin, const vec3_t vector,
- const vec3_t plane_origin, const vec3_t plane_normal,
- vec3_t intersect_point);
-
-void AngleQuaternion( const vec3_t angles, vec4_t quaternion );
-void QuaternionMatrix( const vec4_t quaternion, float (*matrix)[4] );
-void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt );
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/***
+*
+* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
+*
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+* All Rights Reserved.
+*
+****/
+#ifndef __MATHLIB__
+#define __MATHLIB__
+
+// mathlib.h
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef DOUBLEVEC_T
+ typedef double vec_t;
+#else
+ typedef float vec_t;
+#endif
+ //typedef vec_t vec3_t[3]; // x,y,z
+ typedef vec_t vec4_t[4]; // x,y,z,w
+
+#define SIDE_FRONT 0
+#define SIDE_ON 2
+#define SIDE_BACK 1
+#define SIDE_CROSS -2
+
+#define Q_PI 3.14159265358979323846
+
+ extern vec3_t vec3_origin;
+
+ // Use this definition globally
+#define ON_EPSILON 0.01
+#define EQUAL_EPSILON 0.001
+
+ int VectorCompare(vec3_t v1, vec3_t v2);
+
+#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
+#define VectorFill(a,b) { (a)[0]=(b); (a)[1]=(b); (a)[2]=(b);}
+#define VectorAvg(a) ( ( (a)[0] + (a)[1] + (a)[2] ) / 3 )
+#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}
+#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}
+#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}
+#define VectorScale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];(c)[2]=(b)*(a)[2];}
+
+ vec_t Q_rint(vec_t in);
+ vec_t _DotProduct(vec3_t v1, vec3_t v2);
+ void _VectorSubtract(vec3_t va, vec3_t vb, vec3_t out);
+ void _VectorAdd(vec3_t va, vec3_t vb, vec3_t out);
+ void _VectorCopy(vec3_t in, vec3_t out);
+ void _VectorScale(vec3_t v, vec_t scale, vec3_t out);
+
+ double Vector2DLength(vec3_t v);
+ double VectorLength(vec3_t v);
+
+ void VectorMA(vec3_t va, double scale, vec3_t vb, vec3_t vc);
+
+ void CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross);
+ vec_t VectorNormalize(vec3_t v);
+ void VectorInverse(vec3_t v);
+
+ void ClearBounds(vec3_t mins, vec3_t maxs);
+ void AddPointToBounds(vec3_t v, vec3_t mins, vec3_t maxs);
+
+ void AngleMatrix(const vec3_t angles, float matrix[3][4]);
+ void AngleIMatrix(const vec3_t angles, float matrix[3][4]);
+ void R_ConcatTransforms(const float in1[3][4], const float in2[3][4], float out[3][4]);
+
+ void VectorIRotate(const vec3_t in1, const float in2[3][4], vec3_t out);
+ void VectorRotate(const vec3_t in1, const float in2[3][4], vec3_t out);
+
+ void VectorTransform(const vec3_t in1, const float in2[3][4], vec3_t out);
+
+ float DistanceToIntersection(const vec3_t origin, const vec3_t vector,
+ const vec3_t plane_origin, const vec3_t plane_normal);
+ bool VectorIntersectPlane(const vec3_t origin, const vec3_t vector,
+ const vec3_t plane_origin, const vec3_t plane_normal,
+ vec3_t intersect_point);
+
+ void AngleQuaternion(const vec3_t angles, vec4_t quaternion);
+ void QuaternionMatrix(const vec4_t quaternion, float(*matrix)[4]);
+ void QuaternionSlerp(const vec4_t p, vec4_t q, float t, vec4_t qt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Bsp2Rbn/paklib.h b/Bsp2Rbn/paklib.h
index aec01b1..f9bcc41 100644
--- a/Bsp2Rbn/paklib.h
+++ b/Bsp2Rbn/paklib.h
@@ -15,7 +15,7 @@
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License for more details at:
// http://www.gnu.org/copyleft/gpl.html
@@ -34,13 +34,13 @@ header. This is seperated into three, 4 byte blocks as follows:
-Header-
- Signature (4 bytes of char, equals 'PACK' in ALL cases. If it doesn't then
- it is not considered a pack file.)
+ it is not considered a pack file.)
- Directory Offset (4 bytes, single integer. Specifies the position of the
- first of X Directory areas in the file.)
+ first of X Directory areas in the file.)
- Directory Length (4 bytes, single integer. Specifies the length of the X
- dirextory areas.)
+ dirextory areas.)
(Note: We can find the number X by dividing the length by the 64, because each
directory section is 64 bytes. If the mod of this division is not zero then
@@ -49,51 +49,51 @@ header. This is seperated into three, 4 byte blocks as follows:
-Directory section-
- File name (56 bytes of char, specifies the name of the file pointed to by
- the File Position data. Includes path info. ie maps/base1.bsp)
+ the File Position data. Includes path info. ie maps/base1.bsp)
- File Position (4 bytes, single integer. The first byte(address) of the
- file named by File Name)
+ file named by File Name)
- File Length (4 bytes, single integer. The length of the file named by
- File Name)
+ File Name)
Notes: Normally, the header is at the start of the file and the X number of
directory areas at the very end. The file data is usually in between.
- ________________________________
- HEADER starts here ---> | - Signature (4 bytes) |
- | - Directory Offset (4 bytes) |
- | - Directory Length (4 bytes) |
- |________________________________|
- FILE DATA starts here ---> | |
- | |
- | BINARY DATA |
- | (pointed to by the |
- | File Position data) |
- | |
- ~~~~~ ~~~~~
- ~~~~~ ~~~~~
- | |
- | |
- | |
- | |
- |________________________________|
+ ________________________________
+ HEADER starts here ---> | - Signature (4 bytes) |
+ | - Directory Offset (4 bytes) |
+ | - Directory Length (4 bytes) |
+ |________________________________|
+ FILE DATA starts here ---> | |
+ | |
+ | BINARY DATA |
+ | (pointed to by the |
+ | File Position data) |
+ | |
+ ~~~~~ ~~~~~
+ ~~~~~ ~~~~~
+ | |
+ | |
+ | |
+ | |
+ |________________________________|
DIRECTORY SECTION starts here ---> | - File name (56 bytes) |
- | - File Position (4 bytes) |
- | - File Length (4 bytes) |
- |________________________________|
- | - File name (56 bytes) |
- | - File Position (4 bytes) |
- | - File Length (4 bytes) |
- |________________________________|
- | |
- ~~~~~ ~~~~~
- ~~~~~ ~~~~~
- |________________________________|
- | - File name (56 bytes) |
- | - File Position (4 bytes) |
- | - File Length (4 bytes) |
- |________________________________|
+ | - File Position (4 bytes) |
+ | - File Length (4 bytes) |
+ |________________________________|
+ | - File name (56 bytes) |
+ | - File Position (4 bytes) |
+ | - File Length (4 bytes) |
+ |________________________________|
+ | |
+ ~~~~~ ~~~~~
+ ~~~~~ ~~~~~
+ |________________________________|
+ | - File name (56 bytes) |
+ | - File Position (4 bytes) |
+ | - File Length (4 bytes) |
+ |________________________________|
*/
//
@@ -102,34 +102,33 @@ DIRECTORY SECTION starts here ---> | - File name (56 bytes) |
typedef struct
{
- char identification[4]; // should be PACK or KCAP
- int dir_offset; // directory offset
- int dir_length; // directory length
+ char identification[4]; // should be PACK or KCAP
+ int dir_offset; // directory offset
+ int dir_length; // directory length
} pakheader_t;
typedef struct
{
- char filename[56]; // PAK entry filename
- int file_pos; // PAK entry file position
- int file_length; // PAK entry length
+ char filename[56]; // PAK entry filename
+ int file_pos; // PAK entry file position
+ int file_length; // PAK entry length
} pakinfo_t;
typedef struct pakconfig_s
{
- FILE *pakhandle;
- pakheader_t pakheader;
- pakinfo_t *pakinfo;
- int num_entries;
- struct pakconfig_s *next_config;
+ FILE* pakhandle;
+ pakheader_t pakheader;
+ pakinfo_t* pakinfo;
+ int num_entries;
+ struct pakconfig_s* next_config;
} pakconfig_t;
-FILE *P_OpenPak (char *filename);
-int P_ReadPakHeader(FILE *pakhandle, pakheader_t *pakheader);
-void P_ReadPakInfo(FILE *pakhandle, long offset, int num_entries, pakinfo_t *pakinfo);
-void P_ReadPakItem(FILE *pakhandle, pakinfo_t *pakinfo, void *buffer);
+FILE* P_OpenPak(char* filename);
+int P_ReadPakHeader(FILE* pakhandle, pakheader_t* pakheader);
+void P_ReadPakInfo(FILE* pakhandle, long offset, int num_entries, pakinfo_t* pakinfo);
+void P_ReadPakItem(FILE* pakhandle, pakinfo_t* pakinfo, void* buffer);
void Cmd_PakFile(void);
-bool SearchPakFilename(char *filename, pakconfig_t **pakconfig, pakinfo_t **pakinfo);
-bool LoadPakBSPFile(char *filename);
+bool SearchPakFilename(char* filename, pakconfig_t** pakconfig, pakinfo_t** pakinfo);
+bool LoadPakBSPFile(char* filename);
#endif
-
diff --git a/Bsp2Rbn/scriplib.cpp b/Bsp2Rbn/scriplib.cpp
index 2865066..b55e775 100644
--- a/Bsp2Rbn/scriplib.cpp
+++ b/Bsp2Rbn/scriplib.cpp
@@ -2,8 +2,8 @@
*
* Copyright (c) 1998, Valve LLC. All rights reserved.
*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
****/
@@ -18,21 +18,21 @@
/*
=============================================================================
- PARSING STUFF
+ PARSING STUFF
=============================================================================
*/
typedef struct
{
- char filename[1024];
- char *buffer,*script_p,*end_p;
- int line;
+ char filename[1024];
+ char* buffer, * script_p, * end_p;
+ int line;
} script_t;
#define MAX_INCLUDES 8
script_t scriptstack[MAX_INCLUDES];
-script_t *script;
+script_t* script;
int scriptline;
char token[MAXTOKEN];
@@ -44,64 +44,61 @@ qboolean tokenready; // only true if UnGetToken was just cal
AddScriptToStack
==============
*/
-void AddScriptToStack (char *filename)
+void AddScriptToStack(char* filename)
{
- int size;
+ int size;
- script++;
- if (script == &scriptstack[MAX_INCLUDES])
- Error ("script file exceeded MAX_INCLUDES");
- strcpy (script->filename, ExpandPath (filename) );
+ script++;
+ if (script == &scriptstack[MAX_INCLUDES])
+ Error("script file exceeded MAX_INCLUDES");
+ strcpy(script->filename, ExpandPath(filename));
- size = LoadFile (script->filename, (void **)&script->buffer);
+ size = LoadFile(script->filename, (void**)&script->buffer);
-// printf ("entering %s\n", script->filename);
+ // printf ("entering %s\n", script->filename);
- script->line = 1;
+ script->line = 1;
- script->script_p = script->buffer;
- script->end_p = script->buffer + size;
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
}
-
/*
==============
LoadScriptFile
==============
*/
-void LoadScriptFile (char *filename)
+void LoadScriptFile(char* filename)
{
- script = scriptstack;
- AddScriptToStack (filename);
+ script = scriptstack;
+ AddScriptToStack(filename);
- endofscript = false;
- tokenready = false;
+ endofscript = false;
+ tokenready = false;
}
-
/*
==============
ParseFromMemory
==============
*/
-void ParseFromMemory (char *buffer, int size)
+void ParseFromMemory(char* buffer, int size)
{
- script = scriptstack;
- script++;
- if (script == &scriptstack[MAX_INCLUDES])
- Error ("script file exceeded MAX_INCLUDES");
- strcpy (script->filename, "memory buffer" );
-
- script->buffer = buffer;
- script->line = 1;
- script->script_p = script->buffer;
- script->end_p = script->buffer + size;
-
- endofscript = false;
- tokenready = false;
+ script = scriptstack;
+ script++;
+ if (script == &scriptstack[MAX_INCLUDES])
+ Error("script file exceeded MAX_INCLUDES");
+ strcpy(script->filename, "memory buffer");
+
+ script->buffer = buffer;
+ script->line = 1;
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
+
+ endofscript = false;
+ tokenready = false;
}
-
/*
==============
UnGetToken
@@ -116,33 +113,32 @@ GetToken (false);
could cross a line boundary.
==============
*/
-void UnGetToken (void)
+void UnGetToken(void)
{
- tokenready = true;
+ tokenready = true;
}
-
-qboolean EndOfScript (qboolean crossline)
+qboolean EndOfScript(qboolean crossline)
{
- if (!crossline)
- Error ("Line %i is incomplete\n",scriptline+1);
-
- if (!strcmp (script->filename, "memory buffer"))
- {
- endofscript = true;
- return false;
- }
-
- free (script->buffer);
- if (script == scriptstack+1)
- {
- endofscript = true;
- return false;
- }
- script--;
- scriptline = script->line;
-// printf ("returning to %s\n", script->filename);
- return GetToken (crossline);
+ if (!crossline)
+ Error("Line %i is incomplete\n", scriptline + 1);
+
+ if (!strcmp(script->filename, "memory buffer"))
+ {
+ endofscript = true;
+ return false;
+ }
+
+ free(script->buffer);
+ if (script == scriptstack + 1)
+ {
+ endofscript = true;
+ return false;
+ }
+ script--;
+ scriptline = script->line;
+ // printf ("returning to %s\n", script->filename);
+ return GetToken(crossline);
}
/*
@@ -150,92 +146,91 @@ qboolean EndOfScript (qboolean crossline)
GetToken
==============
*/
-qboolean GetToken (qboolean crossline)
+qboolean GetToken(qboolean crossline)
{
- char *token_p;
+ char* token_p;
- if (tokenready) // is a token allready waiting?
- {
- tokenready = false;
- return true;
- }
+ if (tokenready) // is a token allready waiting?
+ {
+ tokenready = false;
+ return true;
+ }
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
+ if (script->script_p >= script->end_p)
+ return EndOfScript(crossline);
-//
-// skip space
-//
+ //
+ // skip space
+ //
skipspace:
- while (*script->script_p <= 32)
- {
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
- if (*script->script_p++ == '\n')
- {
- if (!crossline)
- Error ("Line %i is incomplete\n",scriptline+1);
- scriptline = script->line++;
- }
- }
-
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
-
- if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
- (*script->script_p == '/' && *((script->script_p)+1) == '/')) // also make // a comment field
- {
- if (!crossline)
- Error ("Line %i is incomplete\n",scriptline+1);
- while (*script->script_p++ != '\n')
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
- scriptline = script->line++;
- goto skipspace;
- }
-
-//
-// copy token
-//
- token_p = token;
-
- if (*script->script_p == '"')
- {
- // quoted token
- script->script_p++;
- while (*script->script_p != '"')
- {
- *token_p++ = *script->script_p++;
- if (script->script_p == script->end_p)
- break;
- if (token_p == &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
- }
- script->script_p++;
- }
- else // regular token
- while ( *script->script_p > 32 && *script->script_p != ';')
- {
- *token_p++ = *script->script_p++;
- if (script->script_p == script->end_p)
- break;
- if (token_p == &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
- }
-
- *token_p = 0;
-
- if (!strcmp (token, "$include"))
- {
- GetToken (false);
- AddScriptToStack (token);
- return GetToken (crossline);
- }
-
- return true;
+ while (*script->script_p <= 32)
+ {
+ if (script->script_p >= script->end_p)
+ return EndOfScript(crossline);
+ if (*script->script_p++ == '\n')
+ {
+ if (!crossline)
+ Error("Line %i is incomplete\n", scriptline + 1);
+ scriptline = script->line++;
+ }
+ }
+
+ if (script->script_p >= script->end_p)
+ return EndOfScript(crossline);
+
+ if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
+ (*script->script_p == '/' && *((script->script_p) + 1) == '/')) // also make // a comment field
+ {
+ if (!crossline)
+ Error("Line %i is incomplete\n", scriptline + 1);
+ while (*script->script_p++ != '\n')
+ if (script->script_p >= script->end_p)
+ return EndOfScript(crossline);
+ scriptline = script->line++;
+ goto skipspace;
+ }
+
+ //
+ // copy token
+ //
+ token_p = token;
+
+ if (*script->script_p == '"')
+ {
+ // quoted token
+ script->script_p++;
+ while (*script->script_p != '"')
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error("Token too large on line %i\n", scriptline);
+ }
+ script->script_p++;
+ }
+ else // regular token
+ while (*script->script_p > 32 && *script->script_p != ';')
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error("Token too large on line %i\n", scriptline);
+ }
+
+ *token_p = 0;
+
+ if (!strcmp(token, "$include"))
+ {
+ GetToken(false);
+ AddScriptToStack(token);
+ return GetToken(crossline);
+ }
+
+ return true;
}
-
/*
==============
TokenAvailable
@@ -243,28 +238,26 @@ TokenAvailable
Returns true if there is another token on the line
==============
*/
-qboolean TokenAvailable (void)
+qboolean TokenAvailable(void)
{
- char *search_p;
+ char* search_p;
- search_p = script->script_p;
+ search_p = script->script_p;
- if (search_p >= script->end_p)
- return false;
+ if (search_p >= script->end_p)
+ return false;
- while ( *search_p <= 32)
- {
- if (*search_p == '\n')
- return false;
- search_p++;
- if (search_p == script->end_p)
- return false;
+ while (*search_p <= 32)
+ {
+ if (*search_p == '\n')
+ return false;
+ search_p++;
+ if (search_p == script->end_p)
+ return false;
+ }
- }
-
- if (*search_p == ';')
- return false;
-
- return true;
-}
+ if (*search_p == ';')
+ return false;
+ return true;
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/scriplib.h b/Bsp2Rbn/scriplib.h
index 3200c13..306ba99 100644
--- a/Bsp2Rbn/scriplib.h
+++ b/Bsp2Rbn/scriplib.h
@@ -2,8 +2,8 @@
*
* Copyright (c) 1998, Valve LLC. All rights reserved.
*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
****/
@@ -17,22 +17,19 @@
#ifndef SCRIPLIB_H
#define SCRIPLIB_H
-
#define MAXTOKEN 4096
extern char token[MAXTOKEN];
-extern char *scriptbuffer,*script_p,*scriptend_p;
+extern char* scriptbuffer, * script_p, * scriptend_p;
extern int grabbed;
extern int scriptline;
extern qboolean endofscript;
+void LoadScriptFile(char* filename);
+void ParseFromMemory(char* buffer, int size);
-void LoadScriptFile (char *filename);
-void ParseFromMemory (char *buffer, int size);
-
-qboolean GetToken (qboolean crossline);
-void UnGetToken (void);
-qboolean TokenAvailable (void);
+qboolean GetToken(qboolean crossline);
+void UnGetToken(void);
+qboolean TokenAvailable(void);
#endif // SCRIPLIB_H
-
diff --git a/Bsp2Rbn/studio_model.h b/Bsp2Rbn/studio_model.h
index 3fac790..ad08082 100644
--- a/Bsp2Rbn/studio_model.h
+++ b/Bsp2Rbn/studio_model.h
@@ -1,91 +1,90 @@
-/***
-*
-* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
-*
-* This product contains software technology licensed from Id
-* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
-* All Rights Reserved.
-*
-****/
-
-#ifndef __MATHLIB__
-#include "mathlib.h"
-#endif
-
-#ifndef _STUDIO_H_
-#include "studio.h"
-#endif
-
-#ifndef __STUDIO_MODEL__
-#define __STUDIO_MODEL__
-
-typedef unsigned char byte;
-
-class StudioModel
-{
-public:
- bool Init( char *modelname );
- void DrawModel( void );
- void AdvanceFrame( float dt );
-
- void ExtractBbox( float *mins, float *maxs );
-
- int SetSequence( int iSequence );
- int GetSequence( void );
- void GetSequenceInfo( float *pflFrameRate, float *pflGroundSpeed );
-
- float SetController( int iController, float flValue );
- float SetMouth( float flValue );
- float SetBlending( int iBlender, float flValue );
- int SetBodygroup( int iGroup, int iValue );
- int SetSkin( int iValue );
-
-private:
- // entity settings
- vec3_t m_origin;
- vec3_t m_angles;
- int m_sequence; // sequence index
- float m_frame; // frame
- int m_bodynum; // bodypart selection
- int m_skinnum; // skin group selection
- byte m_controller[4]; // bone controllers
- byte m_blending[2]; // animation blending
- byte m_mouth; // mouth position
-
- // internal data
- studiohdr_t *m_pstudiohdr;
- mstudiomodel_t *m_pmodel;
-
- studiohdr_t *m_ptexturehdr;
- studioseqhdr_t *m_panimhdr[32];
-
- vec4_t m_adj; // FIX: non persistant, make static
-
- studiohdr_t *LoadModel( char *modelname );
- studioseqhdr_t *LoadDemandSequences( char *modelname );
-
- void CalcBoneAdj( void );
- void CalcBoneQuaternion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *q );
- void CalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *pos );
- void CalcRotations ( vec3_t *pos, vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f );
- mstudioanim_t *GetAnim( mstudioseqdesc_t *pseqdesc );
- void SlerpBones( vec4_t q1[], vec3_t pos1[], vec4_t q2[], vec3_t pos2[], float s );
- void SetUpBones ( void );
-
- void DrawPoints( void );
-
- void Lighting (float *lv, int bone, int flags, vec3_t normal);
- void Chrome (int *chrome, int bone, vec3_t normal);
-
- void SetupLighting( void );
-
- void SetupModel ( int bodypart );
-
- void UploadTexture( mstudiotexture_t *ptexture, byte *data, byte *pal );
-};
-
-extern vec3_t g_vright; // needs to be set to viewer's right in order for chrome to work
-extern float g_lambert; // modifier for pseudo-hemispherical lighting
-
-#endif
+/***
+*
+* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
+*
+* This product contains software technology licensed from Id
+* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
+* All Rights Reserved.
+*
+****/
+#ifndef __MATHLIB__
+#include "mathlib.h"
+#endif
+
+#ifndef _STUDIO_H_
+#include "studio.h"
+#endif
+
+#ifndef __STUDIO_MODEL__
+#define __STUDIO_MODEL__
+
+typedef unsigned char byte;
+
+class StudioModel
+{
+public:
+ bool Init(char* modelname);
+ void DrawModel(void);
+ void AdvanceFrame(float dt);
+
+ void ExtractBbox(float* mins, float* maxs);
+
+ int SetSequence(int iSequence);
+ int GetSequence(void);
+ void GetSequenceInfo(float* pflFrameRate, float* pflGroundSpeed);
+
+ float SetController(int iController, float flValue);
+ float SetMouth(float flValue);
+ float SetBlending(int iBlender, float flValue);
+ int SetBodygroup(int iGroup, int iValue);
+ int SetSkin(int iValue);
+
+private:
+ // entity settings
+ vec3_t m_origin;
+ vec3_t m_angles;
+ int m_sequence; // sequence index
+ float m_frame; // frame
+ int m_bodynum; // bodypart selection
+ int m_skinnum; // skin group selection
+ byte m_controller[4]; // bone controllers
+ byte m_blending[2]; // animation blending
+ byte m_mouth; // mouth position
+
+ // internal data
+ studiohdr_t* m_pstudiohdr;
+ mstudiomodel_t* m_pmodel;
+
+ studiohdr_t* m_ptexturehdr;
+ studioseqhdr_t* m_panimhdr[32];
+
+ vec4_t m_adj; // FIX: non persistant, make static
+
+ studiohdr_t* LoadModel(char* modelname);
+ studioseqhdr_t* LoadDemandSequences(char* modelname);
+
+ void CalcBoneAdj(void);
+ void CalcBoneQuaternion(int frame, float s, mstudiobone_t* pbone, mstudioanim_t* panim, float* q);
+ void CalcBonePosition(int frame, float s, mstudiobone_t* pbone, mstudioanim_t* panim, float* pos);
+ void CalcRotations(vec3_t* pos, vec4_t* q, mstudioseqdesc_t* pseqdesc, mstudioanim_t* panim, float f);
+ mstudioanim_t* GetAnim(mstudioseqdesc_t* pseqdesc);
+ void SlerpBones(vec4_t q1[], vec3_t pos1[], vec4_t q2[], vec3_t pos2[], float s);
+ void SetUpBones(void);
+
+ void DrawPoints(void);
+
+ void Lighting(float* lv, int bone, int flags, vec3_t normal);
+ void Chrome(int* chrome, int bone, vec3_t normal);
+
+ void SetupLighting(void);
+
+ void SetupModel(int bodypart);
+
+ void UploadTexture(mstudiotexture_t* ptexture, byte* data, byte* pal);
+};
+
+extern vec3_t g_vright; // needs to be set to viewer's right in order for chrome to work
+extern float g_lambert; // modifier for pseudo-hemispherical lighting
+
+#endif
diff --git a/Bsp2Rbn/trace.cpp b/Bsp2Rbn/trace.cpp
index a132597..34a11f4 100644
--- a/Bsp2Rbn/trace.cpp
+++ b/Bsp2Rbn/trace.cpp
@@ -40,95 +40,94 @@ typedef vec_t vec3_t[3];
#define MAX(a,b) (a > b ? a : b)
#define MIN(a,b) (a < b ? a : b)
-dnode_t *gNode;
+dnode_t* gNode;
// return the leaf node for a point in 3D space... for model rooted on nodenum
-static dleaf_t *TracePointInHull0Leaf(const int num, const vec3_t point)
+static dleaf_t* TracePointInHull0Leaf(const int num, const vec3_t point)
{
- vec_t d;
- dnode_t *node;
- dplane_t *plane;
- int nodenum ;
-
- nodenum = num ;
- // walk through the tree to find the leaf for the point...
- while (nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planenum];
- d = DotProduct(point, plane->normal) - plane->dist;
- if (d > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
-
- gNode = node;
- return &dleafs[-nodenum - 1];
+ vec_t d;
+ dnode_t* node;
+ dplane_t* plane;
+ int nodenum;
+
+ nodenum = num;
+ // walk through the tree to find the leaf for the point...
+ while (nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planenum];
+ d = DotProduct(point, plane->normal) - plane->dist;
+ if (d > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ }
+
+ gNode = node;
+ return &dleafs[-nodenum - 1];
}
// return contents of a coordinate in 3D space... using hull > 0 (collision hulls)
static int TracePointInLeaf(const int hullNumber, const vec3_t point)
{
- int nodenum;
- vec_t d;
- dclipnode_t *node;
- dplane_t *plane;
-
- nodenum = dmodels[0].headnode[hullNumber] ;
- // walk through the tree to find the leaf for the point...
- while (nodenum >= 0)
- {
- node = &dclipnodes[nodenum];
- plane = &dplanes[node->planenum];
- d = DotProduct(point, plane->normal) - plane->dist;
- if (d > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
- return nodenum ;
+ int nodenum;
+ vec_t d;
+ dclipnode_t* node;
+ dplane_t* plane;
+
+ nodenum = dmodels[0].headnode[hullNumber];
+ // walk through the tree to find the leaf for the point...
+ while (nodenum >= 0)
+ {
+ node = &dclipnodes[nodenum];
+ plane = &dplanes[node->planenum];
+ d = DotProduct(point, plane->normal) - plane->dist;
+ if (d > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ }
+ return nodenum;
}
// find the contents of a coordinate in 3D space... using hull > 0 (collision hulls)
// Just a wrapper for TracePointInLeaf
-int BotmanPointContentsInHull(const int hullNumber,const vec3_t coord)
+int BotmanPointContentsInHull(const int hullNumber, const vec3_t coord)
{
- if (hullNumber == point_hull)
- return BotmanPointContents(dmodels[0].headnode[0],coord) ;
+ if (hullNumber == point_hull)
+ return BotmanPointContents(dmodels[0].headnode[0], coord);
- return TracePointInLeaf(hullNumber,coord);
+ return TracePointInLeaf(hullNumber, coord);
}
// find the contents of a coordinate in 3D space... using hull0 (visibility)
int BotmanPointContents(const int nodenum, const vec3_t coord)
{
- dleaf_t *leaf;
+ dleaf_t* leaf;
- leaf = TracePointInHull0Leaf(nodenum,coord) ;
+ leaf = TracePointInHull0Leaf(nodenum, coord);
- // return contents (CONTENTS_EMPTY, CONTENTS_SOLID, CONTENTS_WATER, etc.)
- return leaf->contents;
+ // return contents (CONTENTS_EMPTY, CONTENTS_SOLID, CONTENTS_WATER, etc.)
+ return leaf->contents;
}
-
-int UTIL_PointContents(const Vector & x)
+int UTIL_PointContents(const Vector& x)
{
- vec3_t point ;
- int WorldContent, ModelContent ;
- int ent_index, model_index ;
- char * value ;
+ vec3_t point;
+ int WorldContent, ModelContent;
+ int ent_index, model_index;
+ char* value;
- point[0]=x.x ;
- point[1]=x.y ;
- point[2]=x.z ;
+ point[0] = x.x;
+ point[1] = x.y;
+ point[2] = x.z;
// Find the content in visibility hull of the world (dmodels[0])
- WorldContent = BotmanPointContents(0,point) ;
+ WorldContent = BotmanPointContents(0, point);
// If not empty, return the result
if (WorldContent != CONTENTS_EMPTY)
- return WorldContent ;
+ return WorldContent;
// If CONTENTS_EMPTY, need to do further check for water...
@@ -139,280 +138,277 @@ int UTIL_PointContents(const Vector & x)
value = ValueForKey(&entities[ent_index], "model");
if (value[0]) {
sscanf(value, "*%d", &model_index);
- ModelContent= BotmanPointContents(dmodels[model_index].headnode[0],point);
+ ModelContent = BotmanPointContents(dmodels[model_index].headnode[0], point);
if (ModelContent == CONTENT_WATER) {
-//printf("***Found water !!! (%.0f,%.0f,%.0f)\n",point[0],point[1],point[2]) ;
- return ModelContent ;
+ //printf("***Found water !!! (%.0f,%.0f,%.0f)\n",point[0],point[1],point[2]) ;
+ return ModelContent;
}
}
-
}
- return WorldContent ;
+ return WorldContent;
}
-
-
// trace a line from start to end, fill in trace_t structure with result...
// Should rather use Quake SV_RecursiveHullCheck()
-void BotmanTraceLine(vec3_t start, vec3_t end, botman_trace_t *tr)
+void BotmanTraceLine(vec3_t start, vec3_t end, botman_trace_t* tr)
{
-dleaf_t *startleaf, *endleaf;
-int numsteps, totalsteps;
-vec3_t move, step, position;
-float dist, trace_dist;
-
- memset(tr, 0, sizeof(botman_trace_t));
-
- if ((start[0] < -4095) || (start[0] > 4095) ||
- (start[1] < -4095) || (start[1] > 4095) ||
- (start[2] < -4095) || (start[2] > 4095))
- {
- // start beyond edge of world is INVALID!!!
- fprintf(stderr,"TraceLine: start point beyond edge of world!\n");
- }
-
- if (end[0] > 4095.0f)
- {
- float percent = 4095.0f / end[0];
- end[1] = end[1] * percent;
- end[2] = end[2] * percent;
- end[0] = 4095.0f;
- }
-
- if (end[1] > 4095.0f)
- {
- float percent = 4095.0f / end[1];
- end[0] = end[0] * percent;
- end[2] = end[2] * percent;
- end[1] = 4095.0f;
- }
-
- if (end[2] > 4095.0f)
- {
- float percent = 4095.0f / end[2];
- end[0] = end[0] * percent;
- end[1] = end[1] * percent;
- end[2] = 4095.0f;
- }
-
- if (end[0] < -4095.0f)
- {
- float percent = 4095.0f / end[0];
- end[1] = end[1] * percent;
- end[2] = end[2] * percent;
- end[0] = -4095.0f;
- }
-
- if (end[1] < -4095.0f)
- {
- float percent = 4095.0f / end[1];
- end[0] = end[0] * percent;
- end[2] = end[2] * percent;
- end[1] = -4095.0f;
- }
-
- if (end[2] < -4095.0f)
- {
- float percent = 4095.0f / end[2];
- end[0] = end[0] * percent;
- end[1] = end[1] * percent;
- end[2] = -4095.0f;
- }
-
- // find the starting and ending leafs...
- startleaf = TracePointInHull0Leaf(0,start);
- endleaf = TracePointInHull0Leaf(0,end);
-
- // set endpos, fraction and contents to the default (trace completed)
- VectorCopy(end, tr->endpos);
- tr->fraction = 1.0f;
- tr->contents = endleaf->contents;
-
- if (startleaf->contents == CONTENTS_SOLID)
- tr->startsolid = TRUE;
-
- // is start and end leaf the same (couldn't possibly hit the world)...
- if (startleaf == endleaf) {
- if (startleaf->contents == CONTENTS_SOLID)
- tr->allsolid = TRUE;
- return;
- }
-
- // get the length of each interation of the loop...
- VectorSubtract(end, start, move);
- dist = (float)VectorLength(move);
-
- // determine the number of steps from start to end...
- if (dist > 1.0f)
- numsteps = totalsteps = (int)dist + 1;
- else
- numsteps = totalsteps = 1;
-
- // calculate the length of the step vector...
- VectorScale(move, (float)2/numsteps, step);
-
- VectorCopy(start, position);
-
- while (numsteps)
- {
- VectorAdd(position, step, position);
-
- endleaf = TracePointInHull0Leaf(0,position);
-
- if ((endleaf->contents == CONTENTS_SOLID) || // we hit something solid...
- (endleaf->contents == CONTENTS_SKY)) // we hit the sky
- {
- vec3_t hitpos;
-
- VectorCopy(position, hitpos);
-
- // store the hit position
- VectorCopy(position, tr->hitpos);
-
- // back off one step before solid
- VectorSubtract(position, step, position);
-
- // store the end position and end position contents
- VectorCopy(position, tr->endpos);
- tr->contents = endleaf->contents;
-
- VectorSubtract(position, start, move);
- trace_dist = (float)VectorLength(move);
- tr->fraction = trace_dist / dist;
-
- break; // break out of while loop
- }
-
- numsteps--;
- }
+ dleaf_t* startleaf, * endleaf;
+ int numsteps, totalsteps;
+ vec3_t move, step, position;
+ float dist, trace_dist;
+
+ memset(tr, 0, sizeof(botman_trace_t));
+
+ if ((start[0] < -4095) || (start[0] > 4095) ||
+ (start[1] < -4095) || (start[1] > 4095) ||
+ (start[2] < -4095) || (start[2] > 4095))
+ {
+ // start beyond edge of world is INVALID!!!
+ fprintf(stderr, "TraceLine: start point beyond edge of world!\n");
+ }
+
+ if (end[0] > 4095.0f)
+ {
+ float percent = 4095.0f / end[0];
+ end[1] = end[1] * percent;
+ end[2] = end[2] * percent;
+ end[0] = 4095.0f;
+ }
+
+ if (end[1] > 4095.0f)
+ {
+ float percent = 4095.0f / end[1];
+ end[0] = end[0] * percent;
+ end[2] = end[2] * percent;
+ end[1] = 4095.0f;
+ }
+
+ if (end[2] > 4095.0f)
+ {
+ float percent = 4095.0f / end[2];
+ end[0] = end[0] * percent;
+ end[1] = end[1] * percent;
+ end[2] = 4095.0f;
+ }
+
+ if (end[0] < -4095.0f)
+ {
+ float percent = 4095.0f / end[0];
+ end[1] = end[1] * percent;
+ end[2] = end[2] * percent;
+ end[0] = -4095.0f;
+ }
+
+ if (end[1] < -4095.0f)
+ {
+ float percent = 4095.0f / end[1];
+ end[0] = end[0] * percent;
+ end[2] = end[2] * percent;
+ end[1] = -4095.0f;
+ }
+
+ if (end[2] < -4095.0f)
+ {
+ float percent = 4095.0f / end[2];
+ end[0] = end[0] * percent;
+ end[1] = end[1] * percent;
+ end[2] = -4095.0f;
+ }
+
+ // find the starting and ending leafs...
+ startleaf = TracePointInHull0Leaf(0, start);
+ endleaf = TracePointInHull0Leaf(0, end);
+
+ // set endpos, fraction and contents to the default (trace completed)
+ VectorCopy(end, tr->endpos);
+ tr->fraction = 1.0f;
+ tr->contents = endleaf->contents;
+
+ if (startleaf->contents == CONTENTS_SOLID)
+ tr->startsolid = TRUE;
+
+ // is start and end leaf the same (couldn't possibly hit the world)...
+ if (startleaf == endleaf) {
+ if (startleaf->contents == CONTENTS_SOLID)
+ tr->allsolid = TRUE;
+ return;
+ }
+
+ // get the length of each interation of the loop...
+ VectorSubtract(end, start, move);
+ dist = (float)VectorLength(move);
+
+ // determine the number of steps from start to end...
+ if (dist > 1.0f)
+ numsteps = totalsteps = (int)dist + 1;
+ else
+ numsteps = totalsteps = 1;
+
+ // calculate the length of the step vector...
+ VectorScale(move, (float)2 / numsteps, step);
+
+ VectorCopy(start, position);
+
+ while (numsteps)
+ {
+ VectorAdd(position, step, position);
+
+ endleaf = TracePointInHull0Leaf(0, position);
+
+ if ((endleaf->contents == CONTENTS_SOLID) || // we hit something solid...
+ (endleaf->contents == CONTENTS_SKY)) // we hit the sky
+ {
+ vec3_t hitpos;
+
+ VectorCopy(position, hitpos);
+
+ // store the hit position
+ VectorCopy(position, tr->hitpos);
+
+ // back off one step before solid
+ VectorSubtract(position, step, position);
+
+ // store the end position and end position contents
+ VectorCopy(position, tr->endpos);
+ tr->contents = endleaf->contents;
+
+ VectorSubtract(position, start, move);
+ trace_dist = (float)VectorLength(move);
+ tr->fraction = trace_dist / dist;
+
+ break; // break out of while loop
+ }
+
+ numsteps--;
+ }
}
#define TWO_PI 6.2831853f
#define DELTA 0.001f
// find the face where the traceline hit...
-dface_t *TraceLineFindFace(vec3_t start, botman_trace_t *tr)
+dface_t* TraceLineFindFace(vec3_t start, botman_trace_t* tr)
{
- vec3_t v_intersect, v_normalized, v_temp;
- dface_t *return_face = NULL;
- float min_diff = 9999.9f;
+ vec3_t v_intersect, v_normalized, v_temp;
+ dface_t* return_face = NULL;
+ float min_diff = 9999.9f;
- VectorSubtract(tr->endpos, start, v_normalized);
- VectorNormalize(v_normalized);
+ VectorSubtract(tr->endpos, start, v_normalized);
+ VectorNormalize(v_normalized);
- dleaf_t *endleaf = TracePointInHull0Leaf(0,tr->endpos);
+ dleaf_t* endleaf = TracePointInHull0Leaf(0, tr->endpos);
- unsigned short *p = dmarksurfaces + endleaf->firstmarksurface;
+ unsigned short* p = dmarksurfaces + endleaf->firstmarksurface;
- // find a plane with endpos on one side and hitpos on the other side...
- for (int i = 0; i < endleaf->nummarksurfaces; i++)
- {
- int face_idx = *p++;
-
- dface_t *face = &dfaces[face_idx];
+ // find a plane with endpos on one side and hitpos on the other side...
+ for (int i = 0; i < endleaf->nummarksurfaces; i++)
+ {
+ int face_idx = *p++;
- dplane_t *plane = &dplanes[face->planenum];
+ dface_t* face = &dfaces[face_idx];
- float d1 = DotProduct(tr->endpos, plane->normal) - plane->dist;
- float d2 = DotProduct(tr->hitpos, plane->normal) - plane->dist;
+ dplane_t* plane = &dplanes[face->planenum];
- if ((d1 > 0 && d2 <= 0)||(d1 <= 0 && d2 > 0))
- {
- // found a plane, find the intersection point in the plane...
+ float d1 = DotProduct(tr->endpos, plane->normal) - plane->dist;
+ float d2 = DotProduct(tr->hitpos, plane->normal) - plane->dist;
- vec3_t plane_origin, v_angle1, v_angle2;
+ if ((d1 > 0 && d2 <= 0) || (d1 <= 0 && d2 > 0))
+ {
+ // found a plane, find the intersection point in the plane...
- VectorScale(plane->normal, plane->dist, plane_origin);
+ vec3_t plane_origin, v_angle1, v_angle2;
- float dist = DistanceToIntersection(start, v_normalized, plane_origin, plane->normal);
+ VectorScale(plane->normal, plane->dist, plane_origin);
- if (dist < 0)
- return NULL; // can't find intersection
+ float dist = DistanceToIntersection(start, v_normalized, plane_origin, plane->normal);
- VectorScale(v_normalized, dist, v_temp);
- VectorAdd(start, v_temp, v_intersect);
+ if (dist < 0)
+ return NULL; // can't find intersection
- // loop through all of the vertexes of all the edges of this face and
- // find the angle between vertex-n, v_intersect and vertex-n+1, then add
- // all these angles together. if the sum of these angles is 360 degrees
- // (or 2 PI radians), then the intersect point lies within that polygon.
+ VectorScale(v_normalized, dist, v_temp);
+ VectorAdd(start, v_temp, v_intersect);
- float angle_sum = 0.0f;
+ // loop through all of the vertexes of all the edges of this face and
+ // find the angle between vertex-n, v_intersect and vertex-n+1, then add
+ // all these angles together. if the sum of these angles is 360 degrees
+ // (or 2 PI radians), then the intersect point lies within that polygon.
- // loop though all of the edges, getting the vertexes...
- for (int edge_index = 0; edge_index < face->numedges; edge_index++)
- {
- vec3_t vertex1, vertex2;
+ float angle_sum = 0.0f;
- // get the coordinates of the vertex of this edge...
- int edge = dsurfedges[face->firstedge + edge_index];
+ // loop though all of the edges, getting the vertexes...
+ for (int edge_index = 0; edge_index < face->numedges; edge_index++)
+ {
+ vec3_t vertex1, vertex2;
- if (edge < 0)
- {
- edge = -edge;
- dedge_t* e = &dedges[edge];
- VectorCopy(dvertexes[e->v[1]].point, vertex1);
- VectorCopy(dvertexes[e->v[0]].point, vertex2);
- }
- else
- {
- dedge_t* e = &dedges[edge];
- VectorCopy(dvertexes[e->v[0]].point, vertex1);
- VectorCopy(dvertexes[e->v[1]].point, vertex2);
- }
+ // get the coordinates of the vertex of this edge...
+ int edge = dsurfedges[face->firstedge + edge_index];
- // now create vectors from the vertexes to the plane intersect point...
- VectorSubtract(vertex1, v_intersect, v_angle1);
- VectorSubtract(vertex2, v_intersect, v_angle2);
+ if (edge < 0)
+ {
+ edge = -edge;
+ dedge_t* e = &dedges[edge];
+ VectorCopy(dvertexes[e->v[1]].point, vertex1);
+ VectorCopy(dvertexes[e->v[0]].point, vertex2);
+ }
+ else
+ {
+ dedge_t* e = &dedges[edge];
+ VectorCopy(dvertexes[e->v[0]].point, vertex1);
+ VectorCopy(dvertexes[e->v[1]].point, vertex2);
+ }
- VectorNormalize(v_angle1);
- VectorNormalize(v_angle2);
+ // now create vectors from the vertexes to the plane intersect point...
+ VectorSubtract(vertex1, v_intersect, v_angle1);
+ VectorSubtract(vertex2, v_intersect, v_angle2);
- // find the angle between these vectors...
- float angle = DotProduct(v_angle1, v_angle2);
+ VectorNormalize(v_angle1);
+ VectorNormalize(v_angle2);
- angle = (float)acos(angle);
+ // find the angle between these vectors...
+ float angle = DotProduct(v_angle1, v_angle2);
- angle_sum += angle;
+ angle = (float)acos(angle);
- edge++;
- }
+ angle_sum += angle;
- // is the sum of the angles 360 degrees (2 PI)?...
- if ((angle_sum >= (TWO_PI - DELTA)) && (angle_sum <= (TWO_PI + DELTA)))
- {
- // find the difference between the sum and 2 PI...
- float diff = (float)fabs(angle_sum - TWO_PI);
+ edge++;
+ }
- if (diff < min_diff) // is this the BEST so far?...
- {
- min_diff = diff;
- return_face = face;
- }
- }
- }
- }
+ // is the sum of the angles 360 degrees (2 PI)?...
+ if ((angle_sum >= (TWO_PI - DELTA)) && (angle_sum <= (TWO_PI + DELTA)))
+ {
+ // find the difference between the sum and 2 PI...
+ float diff = (float)fabs(angle_sum - TWO_PI);
+
+ if (diff < min_diff) // is this the BEST so far?...
+ {
+ min_diff = diff;
+ return_face = face;
+ }
+ }
+ }
+ }
- return return_face;
+ return return_face;
}
-static void ConvertTraceResult(botman_trace_t * tr, TraceResult * ptr)
+static void ConvertTraceResult(botman_trace_t* tr, TraceResult* ptr)
{
- ptr->fAllSolid = tr->allsolid ;
- ptr->fStartSolid = tr->startsolid ;
- ptr->fInOpen = tr->contents == CONTENTS_EMPTY ; // TO BE FIXED
- ptr->fInWater = tr->contents == CONTENTS_WATER ; // ????
- ptr->flFraction = tr->fraction ;
- ptr->vecEndPos[0] = tr->endpos[0] ;
- ptr->vecEndPos[1] = tr->endpos[1] ;
- ptr->vecEndPos[2] = tr->endpos[2] ;
- ptr->flPlaneDist = 0.0f ; // TO BE FIXED ?
- ptr->vecPlaneNormal[0] = 0 ; // TO BE FIXED
- ptr->vecPlaneNormal[1] = 0 ; // TO BE FIXED
- ptr->vecPlaneNormal[2] = 0 ; // TO BE FIXED
- ptr->pHit = NULL ; // TO BE FIXED
- ptr->iHitgroup = 0 ;
+ ptr->fAllSolid = tr->allsolid;
+ ptr->fStartSolid = tr->startsolid;
+ ptr->fInOpen = tr->contents == CONTENTS_EMPTY; // TO BE FIXED
+ ptr->fInWater = tr->contents == CONTENTS_WATER; // ????
+ ptr->flFraction = tr->fraction;
+ ptr->vecEndPos[0] = tr->endpos[0];
+ ptr->vecEndPos[1] = tr->endpos[1];
+ ptr->vecEndPos[2] = tr->endpos[2];
+ ptr->flPlaneDist = 0.0f; // TO BE FIXED ?
+ ptr->vecPlaneNormal[0] = 0; // TO BE FIXED
+ ptr->vecPlaneNormal[1] = 0; // TO BE FIXED
+ ptr->vecPlaneNormal[2] = 0; // TO BE FIXED
+ ptr->pHit = NULL; // TO BE FIXED
+ ptr->iHitgroup = 0;
}
/*
@@ -421,23 +417,23 @@ SV_HullPointContents
==================
*/
-static int SV_HullPointContents (int nodenum, vec3_t p)
+static int SV_HullPointContents(int nodenum, vec3_t p)
{
float d;
- dclipnode_t *node;
- dplane_t *plane;
+ dclipnode_t* node;
+ dplane_t* plane;
while (nodenum >= 0)
{
if (nodenum > numclipnodes) {
- fprintf(stderr,"SV_HullPointContents: bad node number");
- exit(1) ;
+ fprintf(stderr, "SV_HullPointContents: bad node number");
+ exit(1);
}
-
+
node = &dclipnodes[nodenum];
plane = &dplanes[node->planenum];
- d = DotProduct (plane->normal, p) - plane->dist;
+ d = DotProduct(plane->normal, p) - plane->dist;
if (d < 0)
nodenum = node->children[1];
else
@@ -455,14 +451,14 @@ SV_RecursiveHullCheck
==================
*/
-qboolean SV_RecursiveHullCheck (int hullNumber, // Id of hull, 1 = human, ...
+qboolean SV_RecursiveHullCheck(int hullNumber, // Id of hull, 1 = human, ...
int nodenum, // Clip node to analyse from
float p1f, float p2f, // Initialized to 0 & 1
vec3_t p1, vec3_t p2, // P1 = start, P2 = end
- TraceResult *trace)
+ TraceResult* trace)
{
- dclipnode_t *node;
- dplane_t *plane;
+ dclipnode_t* node;
+ dplane_t* plane;
float t1, t2;
float frac;
int i;
@@ -470,12 +466,12 @@ qboolean SV_RecursiveHullCheck (int hullNumber, // Id of hull, 1 = human, ...
int side;
float midf;
- if ((hullNumber < human_hull) || (hullNumber > head_hull)) {
- fprintf(stderr,"Wrong hullNumber in SV_RecursiveHullCheck\n") ;
- exit(1) ;
+ if ((hullNumber < human_hull) || (hullNumber > head_hull)) {
+ fprintf(stderr, "Wrong hullNumber in SV_RecursiveHullCheck\n");
+ exit(1);
}
-// check for empty
+ // check for empty
if (nodenum < 0)
{
if (nodenum != CONTENTS_SOLID)
@@ -492,125 +488,126 @@ qboolean SV_RecursiveHullCheck (int hullNumber, // Id of hull, 1 = human, ...
}
if (nodenum > numclipnodes) {
- fprintf(stderr,"SV_RecursiveHullCheck: bad node number");
- exit(1) ;
+ fprintf(stderr, "SV_RecursiveHullCheck: bad node number");
+ exit(1);
}
-//
-// find the point distances
-//
+ //
+ // find the point distances
+ //
node = &dclipnodes[nodenum];
if ((node->planenum > numplanes) || (node->planenum < 0)) {
- fprintf(stderr,"SV_RecursiveHullCheck: bad plane number");
- exit(1) ;
+ fprintf(stderr, "SV_RecursiveHullCheck: bad plane number");
+ exit(1);
}
plane = &dplanes[node->planenum];
- t1 = DotProduct (plane->normal, p1) - plane->dist;
- t2 = DotProduct (plane->normal, p2) - plane->dist;
-
+ t1 = DotProduct(plane->normal, p1) - plane->dist;
+ t2 = DotProduct(plane->normal, p2) - plane->dist;
+
// Check whether P1 & P2 are on the same side of the plane
// Then, continue to check in this smaller space
if (t1 >= 0 && t2 >= 0)
- return SV_RecursiveHullCheck (hullNumber, node->children[0], p1f, p2f, p1, p2, trace);
+ return SV_RecursiveHullCheck(hullNumber, node->children[0], p1f, p2f, p1, p2, trace);
if (t1 < 0 && t2 < 0)
- return SV_RecursiveHullCheck (hullNumber, node->children[1], p1f, p2f, p1, p2, trace);
+ return SV_RecursiveHullCheck(hullNumber, node->children[1], p1f, p2f, p1, p2, trace);
// P1 & P2 are on opposite side of the plane...
if (t1 == t2) {
- fprintf(stderr,"SV_RecursiveHullCheck: same distance from plane");
- exit(1) ;
+ fprintf(stderr, "SV_RecursiveHullCheck: same distance from plane");
+ exit(1);
}
-// put the crosspoint DIST_EPSILON pixels on the near side
+ // put the crosspoint DIST_EPSILON pixels on the near side
if (t1 < 0.0)
- frac = (t1 + DIST_EPSILON)/(t1-t2);
+ frac = (t1 + DIST_EPSILON) / (t1 - t2);
else
- frac = (t1 - DIST_EPSILON)/(t1-t2);
+ frac = (t1 - DIST_EPSILON) / (t1 - t2);
if (frac < 0.0)
frac = 0.0;
if (frac > 1.0)
frac = 1.0;
-
- midf = p1f + (p2f - p1f)*frac;
- for (i=0 ; i<3 ; i++)
- mid[i] = p1[i] + frac*(p2[i] - p1[i]);
+
+ midf = p1f + (p2f - p1f) * frac;
+ for (i = 0; i < 3; i++)
+ mid[i] = p1[i] + frac * (p2[i] - p1[i]);
side = (t1 < 0);
-// move up to the node
- if (!SV_RecursiveHullCheck (hullNumber, node->children[side], p1f, midf, p1, mid, trace) )
+ // move up to the node
+ if (!SV_RecursiveHullCheck(hullNumber, node->children[side], p1f, midf, p1, mid, trace))
return false;
- if (SV_HullPointContents (node->children[side^1], mid) != CONTENTS_SOLID)
- // go past the node
- return SV_RecursiveHullCheck (hullNumber, node->children[side^1], midf, p2f, mid, p2, trace);
-
+ if (SV_HullPointContents(node->children[side ^ 1], mid) != CONTENTS_SOLID)
+ // go past the node
+ return SV_RecursiveHullCheck(hullNumber, node->children[side ^ 1], midf, p2f, mid, p2, trace);
+
if (trace->fAllSolid)
return false; // never got out of the solid area
-
+
//==================
// the other side of the node is solid, this is the impact point
//==================
if (!side)
{
- VectorCopy (plane->normal, trace->vecPlaneNormal);
+ VectorCopy(plane->normal, trace->vecPlaneNormal);
trace->flPlaneDist = plane->dist;
}
else
{
- VectorSubtract (vec3_origin, plane->normal, trace->vecPlaneNormal);
+ VectorSubtract(vec3_origin, plane->normal, trace->vecPlaneNormal);
trace->flPlaneDist = -plane->dist;
}
// If mid is SOLID, move mid backwards until it is in EMPTY space
- while (SV_HullPointContents (dmodels[0].headnode[hullNumber], mid) == CONTENTS_SOLID)
+ while (SV_HullPointContents(dmodels[0].headnode[hullNumber], mid) == CONTENTS_SOLID)
{
frac -= 0.1;
if (frac < 0.0) // shouldn't really happen, but does occasionally
{
-// fprintf(stderr,"SV_RecursiveHullCheck(): backup past 0\n");
+ // fprintf(stderr,"SV_RecursiveHullCheck(): backup past 0\n");
break; // Exit loop immediately
}
// Adjust mid to reflect the value of frac
- midf = p1f + (p2f - p1f)*frac;
- for (i=0 ; i<3 ; i++)
- mid[i] = p1[i] + frac*(p2[i] - p1[i]);
+ midf = p1f + (p2f - p1f) * frac;
+ for (i = 0; i < 3; i++)
+ mid[i] = p1[i] + frac * (p2[i] - p1[i]);
}
trace->flFraction = midf;
- VectorCopy (mid, trace->vecEndPos);
+ VectorCopy(mid, trace->vecEndPos);
return false;
}
-void UTIL_TraceHull (const Vector & vecStart, const Vector & vecEnd,
- IGNORE_MONSTERS igmon, int hullNumber, edict_t * pentIgnore,
- TraceResult * ptr)
+void UTIL_TraceHull(const Vector& vecStart, const Vector& vecEnd,
+ IGNORE_MONSTERS igmon, int hullNumber, edict_t* pentIgnore,
+ TraceResult* ptr)
{
- vec3_t start, end ;
- botman_trace_t tr ;
-
- start[0]=vecStart.x ;
- start[1]=vecStart.y ;
- start[2]=vecStart.z ;
- end[0]=vecEnd.x ;
- end[1]=vecEnd.y ;
- end[2]=vecEnd.z ;
- memset(&tr,0,sizeof(botman_trace_t)) ;
- tr.fraction=1.0 ;
+ vec3_t start, end;
+ botman_trace_t tr;
+
+ start[0] = vecStart.x;
+ start[1] = vecStart.y;
+ start[2] = vecStart.z;
+ end[0] = vecEnd.x;
+ end[1] = vecEnd.y;
+ end[2] = vecEnd.z;
+ memset(&tr, 0, sizeof(botman_trace_t));
+ tr.fraction = 1.0;
if (hullNumber == point_hull) {
- BotmanTraceLine(start, end, &tr) ;
- ConvertTraceResult(&tr,ptr) ;
- } else {
- TraceResult EntTrace ;
- int ent_index, model_index ;
- char * value ;
+ BotmanTraceLine(start, end, &tr);
+ ConvertTraceResult(&tr, ptr);
+ }
+ else {
+ TraceResult EntTrace;
+ int ent_index, model_index;
+ char* value;
// Set the TraceResult default values
- memset(ptr,0,sizeof(TraceResult)) ;
- ptr->flFraction = 1.0 ;
- ptr->fAllSolid = true ;
- SV_RecursiveHullCheck(hullNumber, dmodels[0].headnode[hullNumber],
+ memset(ptr, 0, sizeof(TraceResult));
+ ptr->flFraction = 1.0;
+ ptr->fAllSolid = true;
+ SV_RecursiveHullCheck(hullNumber, dmodels[0].headnode[hullNumber],
0.0, 1.0, start, end, ptr);
// loop through all the entities looking for "func_wall"...
@@ -620,18 +617,15 @@ void UTIL_TraceHull (const Vector & vecStart, const Vector & vecEnd,
value = ValueForKey(&entities[ent_index], "model");
if (value[0]) {
sscanf(value, "*%d", &model_index);
- memset(&EntTrace,0,sizeof(TraceResult)) ;
- EntTrace.flFraction = 1.0 ;
- EntTrace.fAllSolid = true ;
+ memset(&EntTrace, 0, sizeof(TraceResult));
+ EntTrace.flFraction = 1.0;
+ EntTrace.fAllSolid = true;
SV_RecursiveHullCheck(hullNumber, dmodels[model_index].headnode[hullNumber],
0.0, 1.0, start, end, &EntTrace);
if (EntTrace.flFraction < ptr->flFraction)
- memcpy(ptr,&EntTrace,sizeof(TraceResult)) ;
+ memcpy(ptr, &EntTrace, sizeof(TraceResult));
}
-
}
-
}
- return ;
-}
-
+ return;
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/trace.h b/Bsp2Rbn/trace.h
index f21a049..356e6fd 100644
--- a/Bsp2Rbn/trace.h
+++ b/Bsp2Rbn/trace.h
@@ -15,7 +15,7 @@
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License for more details at:
// http://www.gnu.org/copyleft/gpl.html
@@ -29,18 +29,17 @@
typedef struct
{
- bool allsolid; /* if true, plane is not valid */
- bool startsolid; /* if true, the initial point was in a solid area */
- float fraction; /* time completed, 1.0 = didn't hit anything */
- vec3_t hitpos; /* surface hit position (in solid) */
- vec3_t endpos; /* final position (not in solid) */
- int contents; /* contents of endpos */
+ bool allsolid; /* if true, plane is not valid */
+ bool startsolid; /* if true, the initial point was in a solid area */
+ float fraction; /* time completed, 1.0 = didn't hit anything */
+ vec3_t hitpos; /* surface hit position (in solid) */
+ vec3_t endpos; /* final position (not in solid) */
+ int contents; /* contents of endpos */
} botman_trace_t;
int BotmanPointContents(const int nodenum, const vec3_t coord);
-int BotmanPointContentsInHull(const int hullNumber,const vec3_t coord);
-void BotmanTraceLine (vec3_t start, vec3_t end, botman_trace_t *trace);
-dface_t *TraceLineFindFace(vec3_t start, botman_trace_t *tr);
+int BotmanPointContentsInHull(const int hullNumber, const vec3_t coord);
+void BotmanTraceLine(vec3_t start, vec3_t end, botman_trace_t* trace);
+dface_t* TraceLineFindFace(vec3_t start, botman_trace_t* tr);
#endif
-
diff --git a/Bsp2Rbn/util.cpp b/Bsp2Rbn/util.cpp
index 6bc5e45..9a5167d 100644
--- a/Bsp2Rbn/util.cpp
+++ b/Bsp2Rbn/util.cpp
@@ -21,7 +21,7 @@
**
* DISCLAIMER
*
- * History, Information & Credits:
+ * History, Information & Credits:
* RealBot is based partially upon the HPB-Bot Template #3 by Botman
* Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
* Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
@@ -33,9 +33,9 @@
*
* Pierre Marie Baty
* Count-Floyd
- *
+ *
* !! BOTS-UNITED FOREVER !!
- *
+ *
* This project is open-source, it is protected under the GPL license;
* By using this source-code you agree that you will ALWAYS release the
* source-code with your project.
@@ -49,8 +49,8 @@
#ifdef __linux__
#include
#else
-char * basename(char *) ;
-char * dirname(char *) ;
+char* basename(char*);
+char* dirname(char*);
#endif
#include
#include
@@ -85,475 +85,473 @@ int gmsgShowMenu = 0;
#ifndef __linux__
// 21/07/04 Whistler
// Handle both \ and / as separator
-char * basename(char * s)
+char* basename(char* s)
{
- char * fs ;
-
- if ((s == NULL) || (*s == 0)) return "." ;
- if (strcmp(s,"\\") == 0) return s ;
- if (strcmp(s,"/") == 0) return s ;
- fs = strrchr(s,'\\') ;
- if (fs == NULL) fs = strrchr(s,'/') ;
- if (fs == NULL) return s ;
- return fs + 1 ;
+ char* fs;
+
+ if ((s == NULL) || (*s == 0)) return ".";
+ if (strcmp(s, "\\") == 0) return s;
+ if (strcmp(s, "/") == 0) return s;
+ fs = strrchr(s, '\\');
+ if (fs == NULL) fs = strrchr(s, '/');
+ if (fs == NULL) return s;
+ return fs + 1;
}
-char * dirname(char * s)
+char* dirname(char* s)
{
- char * fs ;
+ char* fs;
if ((s == NULL) || (*s == 0)) return ".";
- if (strcmp(s,"\\") == 0) return s;
- if (strcmp(s,"/") == 0) return s;
- fs = strrchr(s,'\\');
- if (fs == NULL) fs = strrchr(s,'/');
+ if (strcmp(s, "\\") == 0) return s;
+ if (strcmp(s, "/") == 0) return s;
+ fs = strrchr(s, '\\');
+ if (fs == NULL) fs = strrchr(s, '/');
if (fs == NULL) return ".";
- * fs = 0;
- return s ;
+ *fs = 0;
+ return s;
}
#endif
-Vector UTIL_VecToAngles (const Vector & vec)
+Vector UTIL_VecToAngles(const Vector& vec)
{
- float rgflVecOut[3];
- VEC_TO_ANGLES (vec, rgflVecOut);
- return Vector (rgflVecOut);
+ float rgflVecOut[3];
+ VEC_TO_ANGLES(vec, rgflVecOut);
+ return Vector(rgflVecOut);
}
// Overloaded to add IGNORE_GLASS
void
-UTIL_TraceLine (const Vector & vecStart, const Vector & vecEnd,
- IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass,
- edict_t * pentIgnore, TraceResult * ptr)
+UTIL_TraceLine(const Vector& vecStart, const Vector& vecEnd,
+ IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass,
+ edict_t* pentIgnore, TraceResult* ptr)
{
- TRACE_LINE (vecStart, vecEnd,
- (igmon ==
- ignore_monsters ? TRUE : FALSE) | (ignoreGlass ? 0x100 : 0),
- pentIgnore, ptr);
+ TRACE_LINE(vecStart, vecEnd,
+ (igmon ==
+ ignore_monsters ? TRUE : FALSE) | (ignoreGlass ? 0x100 : 0),
+ pentIgnore, ptr);
}
void
-UTIL_TraceLine (const Vector & vecStart, const Vector & vecEnd,
- IGNORE_MONSTERS igmon, edict_t * pentIgnore,
- TraceResult * ptr)
+UTIL_TraceLine(const Vector& vecStart, const Vector& vecEnd,
+ IGNORE_MONSTERS igmon, edict_t* pentIgnore,
+ TraceResult* ptr)
{
- TRACE_LINE (vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE),
- pentIgnore, ptr);
+ TRACE_LINE(vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE),
+ pentIgnore, ptr);
}
void
-UTIL_MakeVectors (const Vector & vecAngles)
+UTIL_MakeVectors(const Vector& vecAngles)
{
- MAKE_VECTORS (vecAngles);
+ MAKE_VECTORS(vecAngles);
}
-edict_t *
-UTIL_FindEntityInSphere (edict_t * pentStart, const Vector & vecCenter,
- float flRadius)
+edict_t*
+UTIL_FindEntityInSphere(edict_t* pentStart, const Vector& vecCenter,
+ float flRadius)
{
- edict_t *pentEntity;
+ edict_t* pentEntity;
- pentEntity = FIND_ENTITY_IN_SPHERE (pentStart, vecCenter, flRadius);
+ pentEntity = FIND_ENTITY_IN_SPHERE(pentStart, vecCenter, flRadius);
- if (!FNullEnt (pentEntity))
- return pentEntity;
+ if (!FNullEnt(pentEntity))
+ return pentEntity;
- return NULL;
+ return NULL;
}
-edict_t *
-UTIL_FindEntityByString (edict_t * pentStart, const char *szKeyword,
- const char *szValue)
+edict_t*
+UTIL_FindEntityByString(edict_t* pentStart, const char* szKeyword,
+ const char* szValue)
{
- edict_t *pentEntity;
+ edict_t* pentEntity;
- pentEntity = FIND_ENTITY_BY_STRING (pentStart, szKeyword, szValue);
+ pentEntity = FIND_ENTITY_BY_STRING(pentStart, szKeyword, szValue);
- if (!FNullEnt (pentEntity))
- return pentEntity;
- return NULL;
+ if (!FNullEnt(pentEntity))
+ return pentEntity;
+ return NULL;
}
-edict_t *
-UTIL_FindEntityByClassname (edict_t * pentStart, const char *szName)
+edict_t*
+UTIL_FindEntityByClassname(edict_t* pentStart, const char* szName)
{
- return UTIL_FindEntityByString (pentStart, "classname", szName);
+ return UTIL_FindEntityByString(pentStart, "classname", szName);
}
-edict_t *
-UTIL_FindEntityByTargetname (edict_t * pentStart, const char *szName)
+edict_t*
+UTIL_FindEntityByTargetname(edict_t* pentStart, const char* szName)
{
- return UTIL_FindEntityByString (pentStart, "targetname", szName);
+ return UTIL_FindEntityByString(pentStart, "targetname", szName);
}
void
-UTIL_SetSize (entvars_t * pev, const Vector & vecMin, const Vector & vecMax)
+UTIL_SetSize(entvars_t* pev, const Vector& vecMin, const Vector& vecMax)
{
- SET_SIZE (ENT (pev), vecMin, vecMax);
+ SET_SIZE(ENT(pev), vecMin, vecMax);
}
void
-UTIL_SetOrigin (entvars_t * pev, const Vector & vecOrigin)
+UTIL_SetOrigin(entvars_t* pev, const Vector& vecOrigin)
{
- SET_ORIGIN (ENT (pev), vecOrigin);
+ SET_ORIGIN(ENT(pev), vecOrigin);
}
void
-ClientPrint (edict_t * pEntity, int msg_dest, const char *msg_name)
+ClientPrint(edict_t* pEntity, int msg_dest, const char* msg_name)
{
-
}
void
-UTIL_ClientPrintAll (int msg_dest, const char *msg_name, const char *param1,
- const char *param2, const char *param3,
- const char *param4)
+UTIL_ClientPrintAll(int msg_dest, const char* msg_name, const char* param1,
+ const char* param2, const char* param3,
+ const char* param4)
{
}
void
-UTIL_SayText (const char *pText, edict_t * pEdict)
+UTIL_SayText(const char* pText, edict_t* pEdict)
{
- if (gmsgSayText == 0)
- gmsgSayText = REG_USER_MSG ("SayText", -1);
-
- MESSAGE_BEGIN (MSG_ONE, gmsgSayText, NULL, pEdict);
- WRITE_BYTE (ENTINDEX (pEdict));
- //if (mod_id == FRONTLINE_DLL)
- // WRITE_SHORT(0);
- WRITE_STRING (pText);
- MESSAGE_END ();
+ if (gmsgSayText == 0)
+ gmsgSayText = REG_USER_MSG("SayText", -1);
+
+ MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, pEdict);
+ WRITE_BYTE(ENTINDEX(pEdict));
+ //if (mod_id == FRONTLINE_DLL)
+ // WRITE_SHORT(0);
+ WRITE_STRING(pText);
+ MESSAGE_END();
}
void
-UTIL_HostSay (edict_t * pEntity, int teamonly, char *message)
+UTIL_HostSay(edict_t* pEntity, int teamonly, char* message)
{
- int j;
- char text[128];
- char *pc;
- int sender_team, player_team;
- edict_t *client;
-
- // make sure the text has content
- for (pc = message; pc != NULL && *pc != 0; pc++)
- {
- if (isprint (*pc) && !isspace (*pc))
+ int j;
+ char text[128];
+ char* pc;
+ int sender_team, player_team;
+ edict_t* client;
+
+ // make sure the text has content
+ for (pc = message; pc != NULL && *pc != 0; pc++)
+ {
+ if (isprint(*pc) && !isspace(*pc))
+ {
+ pc = NULL; // we've found an alphanumeric character, so text is valid
+ break;
+ }
+ }
+
+ if (pc != NULL)
+ return; // no character found, so say nothing
+
+ // turn on color set 2 (color on, no sound)
+ if (teamonly)
+ sprintf(text, "%c(TEAM) %s: ", 2, STRING(pEntity->v.netname));
+ else
+ sprintf(text, "%c%s: ", 2, STRING(pEntity->v.netname));
+
+ j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator
+ if ((int)strlen(message) > j)
+ message[j] = 0;
+
+ strcat(text, message);
+ strcat(text, "\n");
+
+ // loop through all players
+ // Start with the first player.
+ // This may return the world in single player if the client types something between levels or during spawn
+ // so check it, or it will infinite loop
+
+ if (gmsgSayText == 0)
+ gmsgSayText = REG_USER_MSG("SayText", -1);
+
+ sender_team = UTIL_GetTeam(pEntity);
+
+ client = NULL;
+ while (((client = UTIL_FindEntityByClassname(client, "player")) != NULL) &&
+ (!FNullEnt(client)))
{
- pc = NULL; // we've found an alphanumeric character, so text is valid
- break;
+ if (client == pEntity) // skip sender of message
+ continue;
+
+ player_team = UTIL_GetTeam(client);
+
+ if (teamonly && (sender_team != player_team))
+ continue;
+
+ MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, client);
+ WRITE_BYTE(ENTINDEX(pEntity));
+ //if (mod_id == FRONTLINE_DLL)
+ // WRITE_SHORT(0);
+ WRITE_STRING(text);
+ MESSAGE_END();
}
- }
-
- if (pc != NULL)
- return; // no character found, so say nothing
-
- // turn on color set 2 (color on, no sound)
- if (teamonly)
- sprintf (text, "%c(TEAM) %s: ", 2, STRING (pEntity->v.netname));
- else
- sprintf (text, "%c%s: ", 2, STRING (pEntity->v.netname));
-
- j = sizeof (text) - 2 - strlen (text); // -2 for /n and null terminator
- if ((int) strlen (message) > j)
- message[j] = 0;
-
- strcat (text, message);
- strcat (text, "\n");
-
- // loop through all players
- // Start with the first player.
- // This may return the world in single player if the client types something between levels or during spawn
- // so check it, or it will infinite loop
-
- if (gmsgSayText == 0)
- gmsgSayText = REG_USER_MSG ("SayText", -1);
-
- sender_team = UTIL_GetTeam (pEntity);
-
- client = NULL;
- while (((client = UTIL_FindEntityByClassname (client, "player")) != NULL) &&
- (!FNullEnt (client)))
- {
- if (client == pEntity) // skip sender of message
- continue;
-
- player_team = UTIL_GetTeam (client);
-
- if (teamonly && (sender_team != player_team))
- continue;
-
- MESSAGE_BEGIN (MSG_ONE, gmsgSayText, NULL, client);
- WRITE_BYTE (ENTINDEX (pEntity));
- //if (mod_id == FRONTLINE_DLL)
- // WRITE_SHORT(0);
- WRITE_STRING (text);
- MESSAGE_END ();
- }
-
- // print to the sending client
- MESSAGE_BEGIN (MSG_ONE, gmsgSayText, NULL, pEntity);
- WRITE_BYTE (ENTINDEX (pEntity));
- //if (mod_id == FRONTLINE_DLL)
- // WRITE_SHORT(0);
- WRITE_STRING (text);
- MESSAGE_END ();
-
- // echo to server console
- g_engfuncs.pfnServerPrint (text);
+
+ // print to the sending client
+ MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, pEntity);
+ WRITE_BYTE(ENTINDEX(pEntity));
+ //if (mod_id == FRONTLINE_DLL)
+ // WRITE_SHORT(0);
+ WRITE_STRING(text);
+ MESSAGE_END();
+
+ // echo to server console
+ g_engfuncs.pfnServerPrint(text);
}
#ifdef DEBUG
-edict_t *
-DBG_EntOfVars (const entvars_t * pev)
+edict_t*
+DBG_EntOfVars(const entvars_t* pev)
{
- if (pev->pContainingEntity != NULL)
- return pev->pContainingEntity;
- ALERT (at_console,
- "entvars_t pContainingEntity is NULL, calling into engine");
- edict_t *pent = (*g_engfuncs.pfnFindEntityByVars) ((entvars_t *) pev);
- if (pent == NULL)
- ALERT (at_console, "DAMN! Even the engine couldn't FindEntityByVars!");
- ((entvars_t *) pev)->pContainingEntity = pent;
- return pent;
+ if (pev->pContainingEntity != NULL)
+ return pev->pContainingEntity;
+ ALERT(at_console,
+ "entvars_t pContainingEntity is NULL, calling into engine");
+ edict_t* pent = (*g_engfuncs.pfnFindEntityByVars) ((entvars_t*)pev);
+ if (pent == NULL)
+ ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!");
+ ((entvars_t*)pev)->pContainingEntity = pent;
+ return pent;
}
#endif //DEBUG
// Is the edict a vip or not?
bool
-UTIL_IsVip (edict_t * pEntity)
+UTIL_IsVip(edict_t* pEntity)
{
- if (mod_id != CSTRIKE_DLL)
- return false;
- else
- {
- char *infobuffer;
- char model_name[32];
+ if (mod_id != CSTRIKE_DLL)
+ return false;
+ else
+ {
+ char* infobuffer;
+ char model_name[32];
- infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer) (pEntity);
- strcpy (model_name, (g_engfuncs.pfnInfoKeyValue (infobuffer, "model")));
+ infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer) (pEntity);
+ strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));
- if (strcmp (model_name, "vip") == 0) // VIP
- return true;
- }
+ if (strcmp(model_name, "vip") == 0) // VIP
+ return true;
+ }
- return false;
+ return false;
}
// return team number 0 through 3 based what MOD uses for team numbers
int
-UTIL_GetTeam (edict_t * pEntity)
+UTIL_GetTeam(edict_t* pEntity)
{
- if (mod_id == CSTRIKE_DLL)
- {
- char *infobuffer;
- char model_name[32];
-
- infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer) (pEntity);
- strcpy (model_name, (g_engfuncs.pfnInfoKeyValue (infobuffer, "model")));
-
- if ((strcmp (model_name, "terror") == 0) || // Phoenix Connektion
- (strcmp (model_name, "arab") == 0) || // old L337 Krew
- (strcmp (model_name, "leet") == 0) || // L337 Krew
- (strcmp (model_name, "artic") == 0) || // Artic Avenger
- (strcmp (model_name, "arctic") == 0) || // Artic Avenger - fix for arctic? - seemed a typo?
- (strcmp (model_name, "guerilla") == 0)) // Gorilla Warfare
- {
- return 0;
- }
- else if ((strcmp (model_name, "urban") == 0) || // Seal Team 6
- (strcmp (model_name, "gsg9") == 0) || // German GSG-9
- (strcmp (model_name, "sas") == 0) || // UK SAS
- (strcmp (model_name, "gign") == 0) || // French GIGN
- (strcmp (model_name, "vip") == 0) || // VIP
- (strcmp (model_name, "spetsnatz") == 0)) // CZ Spetsnatz
+ if (mod_id == CSTRIKE_DLL)
{
- return 1;
+ char* infobuffer;
+ char model_name[32];
+
+ infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer) (pEntity);
+ strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));
+
+ if ((strcmp(model_name, "terror") == 0) || // Phoenix Connektion
+ (strcmp(model_name, "arab") == 0) || // old L337 Krew
+ (strcmp(model_name, "leet") == 0) || // L337 Krew
+ (strcmp(model_name, "artic") == 0) || // Artic Avenger
+ (strcmp(model_name, "arctic") == 0) || // Artic Avenger - fix for arctic? - seemed a typo?
+ (strcmp(model_name, "guerilla") == 0)) // Gorilla Warfare
+ {
+ return 0;
+ }
+ else if ((strcmp(model_name, "urban") == 0) || // Seal Team 6
+ (strcmp(model_name, "gsg9") == 0) || // German GSG-9
+ (strcmp(model_name, "sas") == 0) || // UK SAS
+ (strcmp(model_name, "gign") == 0) || // French GIGN
+ (strcmp(model_name, "vip") == 0) || // VIP
+ (strcmp(model_name, "spetsnatz") == 0)) // CZ Spetsnatz
+ {
+ return 1;
+ }
+ return -1; // return zero if team is unknown
}
- return -1; // return zero if team is unknown
- }
- return 0;
+ return 0;
}
// return class number 0 through N
int
-UTIL_GetClass (edict_t * pEntity)
+UTIL_GetClass(edict_t* pEntity)
{
- char *infobuffer;
- char model_name[32];
+ char* infobuffer;
+ char model_name[32];
- infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer) (pEntity);
- strcpy (model_name, (g_engfuncs.pfnInfoKeyValue (infobuffer, "model")));
+ infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer) (pEntity);
+ strcpy(model_name, (g_engfuncs.pfnInfoKeyValue(infobuffer, "model")));
- return 0;
+ return 0;
}
int
-UTIL_GetBotIndex (edict_t * pEdict)
+UTIL_GetBotIndex(edict_t* pEdict)
{
- int index;
+ int index;
- for (index = 0; index < 32; index++)
- {
- if (bots[index].pEdict == pEdict)
+ for (index = 0; index < 32; index++)
{
- return index;
+ if (bots[index].pEdict == pEdict)
+ {
+ return index;
+ }
}
- }
- return -1; // return -1 if edict is not a bot
+ return -1; // return -1 if edict is not a bot
}
-cBot *
-UTIL_GetBotPointer (edict_t * pEdict)
+cBot*
+UTIL_GetBotPointer(edict_t* pEdict)
{
- int index;
+ int index;
- for (index = 0; index < 32; index++)
- {
- if (bots[index].pEdict == pEdict)
- {
- break;
- }
- }
+ for (index = 0; index < 32; index++)
+ {
+ if (bots[index].pEdict == pEdict)
+ {
+ break;
+ }
+ }
- if (index < 32)
- return (&bots[index]);
+ if (index < 32)
+ return (&bots[index]);
- return NULL; // return NULL if edict is not a bot
+ return NULL; // return NULL if edict is not a bot
}
-bool IsAlive (edict_t * pEdict) {
- // FIX: Make sure the edict is valid and such, else return false:
- return ((pEdict != NULL) && // VALID
- (pEdict->v.deadflag == DEAD_NO) && // NOT DEAD
- (pEdict->v.health > 0) && // ENOUGHT HEALTH
- !(pEdict->v.flags & FL_NOTARGET) && // ?
- (pEdict->v.takedamage != 0)); // CAN TAKE DAMAGE
+bool IsAlive(edict_t* pEdict) {
+ // FIX: Make sure the edict is valid and such, else return false:
+ return ((pEdict != NULL) && // VALID
+ (pEdict->v.deadflag == DEAD_NO) && // NOT DEAD
+ (pEdict->v.health > 0) && // ENOUGHT HEALTH
+ !(pEdict->v.flags & FL_NOTARGET) && // ?
+ (pEdict->v.takedamage != 0)); // CAN TAKE DAMAGE
}
bool
-FInViewCone (Vector * pOrigin, edict_t * pEdict)
+FInViewCone(Vector* pOrigin, edict_t* pEdict)
{
#ifdef EVYISWRONG
-return TRUE ;
+ return TRUE;
#endif
- Vector2D vec2LOS;
- float flDot;
+ Vector2D vec2LOS;
+ float flDot;
- UTIL_MakeVectors (pEdict->v.angles);
+ UTIL_MakeVectors(pEdict->v.angles);
- vec2LOS = (*pOrigin - pEdict->v.origin).Make2D ();
- vec2LOS = vec2LOS.Normalize ();
+ vec2LOS = (*pOrigin - pEdict->v.origin).Make2D();
+ vec2LOS = vec2LOS.Normalize();
- flDot = DotProduct (vec2LOS, gpGlobals->v_forward.Make2D ());
+ flDot = DotProduct(vec2LOS, gpGlobals->v_forward.Make2D());
- if (flDot > 0.50) // 60 degree field of view
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
+ if (flDot > 0.50) // 60 degree field of view
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
}
// FVisible()
bool
-FVisible (const Vector & vecOrigin, edict_t * pEdict)
+FVisible(const Vector& vecOrigin, edict_t* pEdict)
{
#ifdef EVYISWRONG
-return TRUE ;
+ return TRUE;
#endif
- TraceResult tr;
- Vector vecLookerOrigin;
-
- // look through caller's eyes
- vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs;
-
- int bInWater = (UTIL_PointContents (vecOrigin) == CONTENTS_WATER);
- int bLookerInWater =
- (UTIL_PointContents (vecLookerOrigin) == CONTENTS_WATER);
-
- // don't look through water
- if (bInWater != bLookerInWater)
- return FALSE;
-
- UTIL_TraceLine (vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass,
- pEdict, &tr);
-
- if (tr.flFraction != 1.0)
- {
- return FALSE; // Line of sight is not established
- }
- else
- {
- return TRUE; // line of sight is valid.
- }
+ TraceResult tr;
+ Vector vecLookerOrigin;
+
+ // look through caller's eyes
+ vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs;
+
+ int bInWater = (UTIL_PointContents(vecOrigin) == CONTENTS_WATER);
+ int bLookerInWater =
+ (UTIL_PointContents(vecLookerOrigin) == CONTENTS_WATER);
+
+ // don't look through water
+ if (bInWater != bLookerInWater)
+ return FALSE;
+
+ UTIL_TraceLine(vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass,
+ pEdict, &tr);
+
+ if (tr.flFraction != 1.0)
+ {
+ return FALSE; // Line of sight is not established
+ }
+ else
+ {
+ return TRUE; // line of sight is valid.
+ }
}
Vector
-GetGunPosition (edict_t * pEdict)
+GetGunPosition(edict_t* pEdict)
{
- return (pEdict->v.origin + pEdict->v.view_ofs);
+ return (pEdict->v.origin + pEdict->v.view_ofs);
}
void
-UTIL_SelectItem (edict_t * pEdict, char *item_name)
+UTIL_SelectItem(edict_t* pEdict, char* item_name)
{
- /*BotDebug( item_name); */
- FakeClientCommand (pEdict, item_name, NULL, NULL);
+ /*BotDebug( item_name); */
+ FakeClientCommand(pEdict, item_name, NULL, NULL);
}
Vector
-VecBModelOrigin (edict_t * pEdict)
+VecBModelOrigin(edict_t* pEdict)
{
- return pEdict->v.absmin + (pEdict->v.size * 0.5);
+ return pEdict->v.absmin + (pEdict->v.size * 0.5);
}
void
-UTIL_ShowMenu (edict_t * pEdict, int slots, int displaytime, bool needmore,
- char *pText)
+UTIL_ShowMenu(edict_t* pEdict, int slots, int displaytime, bool needmore,
+ char* pText)
{
- if (gmsgShowMenu == 0)
- gmsgShowMenu = REG_USER_MSG ("ShowMenu", -1);
+ if (gmsgShowMenu == 0)
+ gmsgShowMenu = REG_USER_MSG("ShowMenu", -1);
- MESSAGE_BEGIN (MSG_ONE, gmsgShowMenu, NULL, pEdict);
+ MESSAGE_BEGIN(MSG_ONE, gmsgShowMenu, NULL, pEdict);
- WRITE_SHORT (slots);
- WRITE_CHAR (displaytime);
- WRITE_BYTE (needmore);
- WRITE_STRING (pText);
+ WRITE_SHORT(slots);
+ WRITE_CHAR(displaytime);
+ WRITE_BYTE(needmore);
+ WRITE_STRING(pText);
- MESSAGE_END ();
+ MESSAGE_END();
}
void
-UTIL_BuildFileName (char *filename, char *arg1, char *arg2)
+UTIL_BuildFileName(char* filename, char* arg1, char* arg2)
{
+ if (mod_id == VALVE_DLL)
+ strcpy(filename, "valve/");
+
+ else if (mod_id == CSTRIKE_DLL)
+ strcpy(filename, "cstrike/");
- if (mod_id == VALVE_DLL)
- strcpy (filename, "valve/");
-
- else if (mod_id == CSTRIKE_DLL)
- strcpy (filename, "cstrike/");
-
- else
- {
- filename[0] = 0;
- return;
- }
-
- if ((arg1) && (*arg1) && (arg2) && (*arg2))
- {
- strcat (filename, arg1);
- strcat (filename, "/");
- strcat (filename, arg2);
- }
- else if ((arg1) && (*arg1))
- {
- strcat (filename, arg1);
- }
+ else
+ {
+ filename[0] = 0;
+ return;
+ }
+
+ if ((arg1) && (*arg1) && (arg2) && (*arg2))
+ {
+ strcat(filename, arg1);
+ strcat(filename, "/");
+ strcat(filename, arg2);
+ }
+ else if ((arg1) && (*arg1))
+ {
+ strcat(filename, arg1);
+ }
}
// added by Tub
@@ -561,14 +559,14 @@ UTIL_BuildFileName (char *filename, char *arg1, char *arg2)
// Heavily modified in the standalone version
void
-UTIL_BuildFileNameRB (char *subdir, char *filename)
+UTIL_BuildFileNameRB(char* subdir, char* filename)
{
- char * temp, *temp2 ;
+ char* temp, * temp2;
- temp=strdup(subdir);
- temp2=basename(temp) ;
- strcpy(filename,temp2) ;
- free(temp) ;
+ temp = strdup(subdir);
+ temp2 = basename(temp);
+ strcpy(filename, temp2);
+ free(temp);
}
//=========================================================
@@ -576,443 +574,438 @@ UTIL_BuildFileNameRB (char *subdir, char *filename)
// Preceded by LOG: ( timestamp ) < message >
//=========================================================
void
-UTIL_LogPrintf (char *fmt, ...)
+UTIL_LogPrintf(char* fmt, ...)
{
- va_list argptr;
- static char string[1024];
+ va_list argptr;
+ static char string[1024];
- va_start (argptr, fmt);
- vsprintf (string, fmt, argptr);
- va_end (argptr);
+ va_start(argptr, fmt);
+ vsprintf(string, fmt, argptr);
+ va_end(argptr);
- // Print to server console
- ALERT (at_logged, "%s", string);
+ // Print to server console
+ ALERT(at_logged, "%s", string);
}
void
-UTIL_BotPressKey (cBot * pBot, int type) {
- if (type == IN_JUMP || type == IN_DUCK)
- if (pBot->f_freeze_time > gpGlobals->time)
- return; // do nothing when in freezetime
+UTIL_BotPressKey(cBot* pBot, int type) {
+ if (type == IN_JUMP || type == IN_DUCK)
+ if (pBot->f_freeze_time > gpGlobals->time)
+ return; // do nothing when in freezetime
- if (type == IN_JUMP)
- if (pBot->f_may_jump_time > gpGlobals->time)
- return; // do nothing when we may not jump
+ if (type == IN_JUMP)
+ if (pBot->f_may_jump_time > gpGlobals->time)
+ return; // do nothing when we may not jump
- if (type == IN_JUMP && pBot->f_camp_time > gpGlobals->time)
- return; // Do not jump when camping.
+ if (type == IN_JUMP && pBot->f_camp_time > gpGlobals->time)
+ return; // Do not jump when camping.
- // don't jump from ladder
- if (FUNC_IsOnLadder (pBot->pEdict) && type == IN_JUMP)
- return;
+ // don't jump from ladder
+ if (FUNC_IsOnLadder(pBot->pEdict) && type == IN_JUMP)
+ return;
- // KEY: Reload
- if (type == IN_RELOAD) // when reloading, there is NO zooming (when holding a zoomable weapon or a sniper gun)
- {
- if (FUNC_BotHoldsZoomWeapon (pBot)
- || UTIL_GiveWeaponType (pBot->current_weapon.iId) == SNIPER)
+ // KEY: Reload
+ if (type == IN_RELOAD) // when reloading, there is NO zooming (when holding a zoomable weapon or a sniper gun)
+ {
+ if (FUNC_BotHoldsZoomWeapon(pBot)
+ || UTIL_GiveWeaponType(pBot->current_weapon.iId) == SNIPER)
- //pBot->zoomed = ZOOM_NONE; // not zoomed anymore
+ //pBot->zoomed = ZOOM_NONE; // not zoomed anymore
- // FIX: Do not let bots do anything with this weapon for 0.7 second. So the engine can
- // update the information.
- pBot->f_update_weapon_time = gpGlobals->time + 0.7;
- }
+ // FIX: Do not let bots do anything with this weapon for 0.7 second. So the engine can
+ // update the information.
+ pBot->f_update_weapon_time = gpGlobals->time + 0.7;
+ }
- // KEY: End
- pBot->pEdict->v.button |= type;
+ // KEY: End
+ pBot->pEdict->v.button |= type;
- if (type == IN_JUMP)
- {
- if (pBot->f_hold_duck < gpGlobals->time)
- pBot->f_hold_duck = gpGlobals->time + 0.35;
+ if (type == IN_JUMP)
+ {
+ if (pBot->f_hold_duck < gpGlobals->time)
+ pBot->f_hold_duck = gpGlobals->time + 0.35;
- pBot->f_may_jump_time = gpGlobals->time + 0.3;
- }
+ pBot->f_may_jump_time = gpGlobals->time + 0.3;
+ }
}
int
-UTIL_GiveWeaponType (int weapon_id)
+UTIL_GiveWeaponType(int weapon_id)
{
- int kind = NONE;
-
- // Check 1. Is it a knife?
- if (weapon_id == CS_WEAPON_KNIFE)
- kind = KNIFE;
-
- // Check 2, is it a 'tool'?
- if (weapon_id == CS_WEAPON_FLASHBANG ||
- weapon_id == CS_WEAPON_HEGRENADE || weapon_id == CS_WEAPON_SMOKEGRENADE)
- kind = GRENADE;
-
- // Check 3, is it a secondary gun?
- if (weapon_id == CS_WEAPON_P228 ||
- weapon_id == CS_WEAPON_ELITE ||
- weapon_id == CS_WEAPON_UMP45 ||
- weapon_id == CS_WEAPON_USP ||
- weapon_id == CS_WEAPON_GLOCK18 ||
- weapon_id == CS_WEAPON_DEAGLE || weapon_id == CS_WEAPON_FIVESEVEN)
- kind = SECONDARY;
-
- // Check 4, is it a sniper gun?
- if (weapon_id == CS_WEAPON_SCOUT ||
- weapon_id == CS_WEAPON_SG550 ||
- weapon_id == CS_WEAPON_AWP || weapon_id == CS_WEAPON_G3SG1)
- kind = SNIPER;
-
- // When the kind of weapon is still not found, its a primary (in CS)
- if (kind == NONE)
- kind = PRIMARY;
-
- if (weapon_id < 1)
- kind = NONE;
-
- return kind;
+ int kind = NONE;
+
+ // Check 1. Is it a knife?
+ if (weapon_id == CS_WEAPON_KNIFE)
+ kind = KNIFE;
+
+ // Check 2, is it a 'tool'?
+ if (weapon_id == CS_WEAPON_FLASHBANG ||
+ weapon_id == CS_WEAPON_HEGRENADE || weapon_id == CS_WEAPON_SMOKEGRENADE)
+ kind = GRENADE;
+
+ // Check 3, is it a secondary gun?
+ if (weapon_id == CS_WEAPON_P228 ||
+ weapon_id == CS_WEAPON_ELITE ||
+ weapon_id == CS_WEAPON_UMP45 ||
+ weapon_id == CS_WEAPON_USP ||
+ weapon_id == CS_WEAPON_GLOCK18 ||
+ weapon_id == CS_WEAPON_DEAGLE || weapon_id == CS_WEAPON_FIVESEVEN)
+ kind = SECONDARY;
+
+ // Check 4, is it a sniper gun?
+ if (weapon_id == CS_WEAPON_SCOUT ||
+ weapon_id == CS_WEAPON_SG550 ||
+ weapon_id == CS_WEAPON_AWP || weapon_id == CS_WEAPON_G3SG1)
+ kind = SNIPER;
+
+ // When the kind of weapon is still not found, its a primary (in CS)
+ if (kind == NONE)
+ kind = PRIMARY;
+
+ if (weapon_id < 1)
+ kind = NONE;
+
+ return kind;
}
// Return weapon ID (depended on mod)
int
-UTIL_GiveWeaponId (char *name)
+UTIL_GiveWeaponId(char* name)
{
- if (mod_id == CSTRIKE_DLL)
- {
- if (strcmp (name, "weapon_knife") == 0)
- return CS_WEAPON_KNIFE;
-
- if (strcmp (name, "weapon_c4") == 0)
- return CS_WEAPON_C4;
- if (strcmp (name, "weapon_mp5navy") == 0)
- return CS_WEAPON_MP5NAVY;
- if (strcmp (name, "weapon_ak47") == 0)
- return CS_WEAPON_AK47;
- if (strcmp (name, "weapon_m3") == 0)
- return CS_WEAPON_M3;
- if (strcmp (name, "weapon_aug") == 0)
- return CS_WEAPON_AUG;
- if (strcmp (name, "weapon_sg552") == 0)
- return CS_WEAPON_SG552;
- if (strcmp (name, "weapon_m249") == 0)
- return CS_WEAPON_M249;
- if (strcmp (name, "weapon_xm1014") == 0)
- return CS_WEAPON_XM1014;
- if (strcmp (name, "weapon_p90") == 0)
- return CS_WEAPON_P90;
- if (strcmp (name, "weapon_tmp") == 0)
- return CS_WEAPON_TMP;
- if (strcmp (name, "weapon_m4a1") == 0)
- return CS_WEAPON_M4A1;
- if (strcmp (name, "weapon_awp") == 0)
- return CS_WEAPON_AWP;
- if (strcmp (name, "weapon_fiveseven") == 0)
- return CS_WEAPON_FIVESEVEN;
- if (strcmp (name, "weapon_ump45") == 0)
- return CS_WEAPON_UMP45;
- if (strcmp (name, "weapon_sg550") == 0)
- return CS_WEAPON_SG550;
- if (strcmp (name, "weapon_scout") == 0)
- return CS_WEAPON_SCOUT;
- if (strcmp (name, "weapon_mac10") == 0)
- return CS_WEAPON_MAC10;
- if (strcmp (name, "weapon_g3sg1") == 0)
- return CS_WEAPON_G3SG1;
- if (strcmp (name, "weapon_elite") == 0)
- return CS_WEAPON_ELITE;
- if (strcmp (name, "weapon_p228") == 0)
- return CS_WEAPON_P228;
- if (strcmp (name, "weapon_deagle") == 0)
- return CS_WEAPON_DEAGLE;
- if (strcmp (name, "weapon_usp") == 0)
- return CS_WEAPON_USP;
- if (strcmp (name, "weapon_glock18") == 0)
- return CS_WEAPON_GLOCK18;
- // Counter-Strike 1.6
- if (strcmp (name, "weapon_famas") == 0)
- return CS_WEAPON_FAMAS;
- if (strcmp (name, "weapon_galil") == 0)
- return CS_WEAPON_GALIL;
-
- // TODO: Detect shield carrying.
-
- }
-
- return -1;
+ if (mod_id == CSTRIKE_DLL)
+ {
+ if (strcmp(name, "weapon_knife") == 0)
+ return CS_WEAPON_KNIFE;
+
+ if (strcmp(name, "weapon_c4") == 0)
+ return CS_WEAPON_C4;
+ if (strcmp(name, "weapon_mp5navy") == 0)
+ return CS_WEAPON_MP5NAVY;
+ if (strcmp(name, "weapon_ak47") == 0)
+ return CS_WEAPON_AK47;
+ if (strcmp(name, "weapon_m3") == 0)
+ return CS_WEAPON_M3;
+ if (strcmp(name, "weapon_aug") == 0)
+ return CS_WEAPON_AUG;
+ if (strcmp(name, "weapon_sg552") == 0)
+ return CS_WEAPON_SG552;
+ if (strcmp(name, "weapon_m249") == 0)
+ return CS_WEAPON_M249;
+ if (strcmp(name, "weapon_xm1014") == 0)
+ return CS_WEAPON_XM1014;
+ if (strcmp(name, "weapon_p90") == 0)
+ return CS_WEAPON_P90;
+ if (strcmp(name, "weapon_tmp") == 0)
+ return CS_WEAPON_TMP;
+ if (strcmp(name, "weapon_m4a1") == 0)
+ return CS_WEAPON_M4A1;
+ if (strcmp(name, "weapon_awp") == 0)
+ return CS_WEAPON_AWP;
+ if (strcmp(name, "weapon_fiveseven") == 0)
+ return CS_WEAPON_FIVESEVEN;
+ if (strcmp(name, "weapon_ump45") == 0)
+ return CS_WEAPON_UMP45;
+ if (strcmp(name, "weapon_sg550") == 0)
+ return CS_WEAPON_SG550;
+ if (strcmp(name, "weapon_scout") == 0)
+ return CS_WEAPON_SCOUT;
+ if (strcmp(name, "weapon_mac10") == 0)
+ return CS_WEAPON_MAC10;
+ if (strcmp(name, "weapon_g3sg1") == 0)
+ return CS_WEAPON_G3SG1;
+ if (strcmp(name, "weapon_elite") == 0)
+ return CS_WEAPON_ELITE;
+ if (strcmp(name, "weapon_p228") == 0)
+ return CS_WEAPON_P228;
+ if (strcmp(name, "weapon_deagle") == 0)
+ return CS_WEAPON_DEAGLE;
+ if (strcmp(name, "weapon_usp") == 0)
+ return CS_WEAPON_USP;
+ if (strcmp(name, "weapon_glock18") == 0)
+ return CS_WEAPON_GLOCK18;
+ // Counter-Strike 1.6
+ if (strcmp(name, "weapon_famas") == 0)
+ return CS_WEAPON_FAMAS;
+ if (strcmp(name, "weapon_galil") == 0)
+ return CS_WEAPON_GALIL;
+
+ // TODO: Detect shield carrying.
+ }
+
+ return -1;
}
// Return weapon ID (depended on mod)
-char *
-UTIL_GiveWeaponName (int id)
+char*
+UTIL_GiveWeaponName(int id)
{
- if (mod_id == CSTRIKE_DLL)
- {
- if (id == CS_WEAPON_C4)
- return "weapon_c4";
- if (id == CS_WEAPON_MP5NAVY)
- return "weapon_mp5navy";
- if (id == CS_WEAPON_AK47)
- return "weapon_ak47";
- if (id == CS_WEAPON_M3)
- return "weapon_m3";
- if (id == CS_WEAPON_AUG)
- return "weapon_aug";
- if (id == CS_WEAPON_SG552)
- return "weapon_sg552";
- if (id == CS_WEAPON_M249)
- return "weapon_m249";
- if (id == CS_WEAPON_XM1014)
- return "weapon_xm1014";
- if (id == CS_WEAPON_P90)
- return "weapon_p90";
- if (id == CS_WEAPON_TMP)
- return "weapon_tmp";
- if (id == CS_WEAPON_M4A1)
- return "weapon_m4a1";
- if (id == CS_WEAPON_AWP)
- return "weapon_awp";
- if (id == CS_WEAPON_FIVESEVEN)
- return "weapon_fiveseven";
- if (id == CS_WEAPON_UMP45)
- return "weapon_ump45";
- if (id == CS_WEAPON_SG550)
- return "weapon_ag550";
- if (id == CS_WEAPON_SCOUT)
- return "weapon_scout";
- if (id == CS_WEAPON_MAC10)
- return "weapon_mac10";
- if (id == CS_WEAPON_G3SG1)
- return "weapon_g3sg1";
- if (id == CS_WEAPON_ELITE)
- return "weapon_elite";
- if (id == CS_WEAPON_P228)
- return "weapon_p228";
- if (id == CS_WEAPON_DEAGLE)
- return "weapon_deagle";
- if (id == CS_WEAPON_USP)
- return "weapon_usp";
- if (id == CS_WEAPON_GLOCK18)
- return "weapon_glock18";
-
- // Counter-Strike 1.6
- if (id == CS_WEAPON_FAMAS)
- return "weapon_famas";
- if (id == CS_WEAPON_GALIL)
- return "weapon_galil";
-
- // Unconfirmed shield
- if (id == CS_WEAPON_SHIELD)
- return "weapon_shield";
-
- }
-
- return "weapon_knife"; // return knife, always good ;)
+ if (mod_id == CSTRIKE_DLL)
+ {
+ if (id == CS_WEAPON_C4)
+ return "weapon_c4";
+ if (id == CS_WEAPON_MP5NAVY)
+ return "weapon_mp5navy";
+ if (id == CS_WEAPON_AK47)
+ return "weapon_ak47";
+ if (id == CS_WEAPON_M3)
+ return "weapon_m3";
+ if (id == CS_WEAPON_AUG)
+ return "weapon_aug";
+ if (id == CS_WEAPON_SG552)
+ return "weapon_sg552";
+ if (id == CS_WEAPON_M249)
+ return "weapon_m249";
+ if (id == CS_WEAPON_XM1014)
+ return "weapon_xm1014";
+ if (id == CS_WEAPON_P90)
+ return "weapon_p90";
+ if (id == CS_WEAPON_TMP)
+ return "weapon_tmp";
+ if (id == CS_WEAPON_M4A1)
+ return "weapon_m4a1";
+ if (id == CS_WEAPON_AWP)
+ return "weapon_awp";
+ if (id == CS_WEAPON_FIVESEVEN)
+ return "weapon_fiveseven";
+ if (id == CS_WEAPON_UMP45)
+ return "weapon_ump45";
+ if (id == CS_WEAPON_SG550)
+ return "weapon_ag550";
+ if (id == CS_WEAPON_SCOUT)
+ return "weapon_scout";
+ if (id == CS_WEAPON_MAC10)
+ return "weapon_mac10";
+ if (id == CS_WEAPON_G3SG1)
+ return "weapon_g3sg1";
+ if (id == CS_WEAPON_ELITE)
+ return "weapon_elite";
+ if (id == CS_WEAPON_P228)
+ return "weapon_p228";
+ if (id == CS_WEAPON_DEAGLE)
+ return "weapon_deagle";
+ if (id == CS_WEAPON_USP)
+ return "weapon_usp";
+ if (id == CS_WEAPON_GLOCK18)
+ return "weapon_glock18";
+
+ // Counter-Strike 1.6
+ if (id == CS_WEAPON_FAMAS)
+ return "weapon_famas";
+ if (id == CS_WEAPON_GALIL)
+ return "weapon_galil";
+
+ // Unconfirmed shield
+ if (id == CS_WEAPON_SHIELD)
+ return "weapon_shield";
+ }
+
+ return "weapon_knife"; // return knife, always good ;)
}
// Thanks Botman for this code (from forum).
void
-UTIL_BotSprayLogo (edict_t * pEntity, char *logo_name)
+UTIL_BotSprayLogo(edict_t* pEntity, char* logo_name)
{
- int index;
- TraceResult pTrace;
- Vector v_src, v_dest;
- UTIL_MakeVectors (pEntity->v.v_angle);
- v_src = pEntity->v.origin + pEntity->v.view_ofs;
- v_dest = v_src + gpGlobals->v_forward * 80;
- UTIL_TraceLine (v_src, v_dest, ignore_monsters,
- pEntity->v.pContainingEntity, &pTrace);
+ int index;
+ TraceResult pTrace;
+ Vector v_src, v_dest;
+ UTIL_MakeVectors(pEntity->v.v_angle);
+ v_src = pEntity->v.origin + pEntity->v.view_ofs;
+ v_dest = v_src + gpGlobals->v_forward * 80;
+ UTIL_TraceLine(v_src, v_dest, ignore_monsters,
+ pEntity->v.pContainingEntity, &pTrace);
- index = DECAL_INDEX (logo_name);
+ index = DECAL_INDEX(logo_name);
- if (index < 0)
- return;
+ if (index < 0)
+ return;
- if ((pTrace.pHit) && (pTrace.flFraction < 1.0))
- {
- if (pTrace.pHit->v.solid != SOLID_BSP)
- return;
+ if ((pTrace.pHit) && (pTrace.flFraction < 1.0))
+ {
+ if (pTrace.pHit->v.solid != SOLID_BSP)
+ return;
- MESSAGE_BEGIN (MSG_BROADCAST, SVC_TEMPENTITY);
+ MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
- if (index > 255)
- {
- WRITE_BYTE (TE_WORLDDECALHIGH);
- index -= 256;
- }
- else
- WRITE_BYTE (TE_WORLDDECAL);
+ if (index > 255)
+ {
+ WRITE_BYTE(TE_WORLDDECALHIGH);
+ index -= 256;
+ }
+ else
+ WRITE_BYTE(TE_WORLDDECAL);
- WRITE_COORD (pTrace.vecEndPos.x);
- WRITE_COORD (pTrace.vecEndPos.y);
- WRITE_COORD (pTrace.vecEndPos.z);
- WRITE_BYTE (index);
+ WRITE_COORD(pTrace.vecEndPos.x);
+ WRITE_COORD(pTrace.vecEndPos.y);
+ WRITE_COORD(pTrace.vecEndPos.z);
+ WRITE_BYTE(index);
- MESSAGE_END ();
+ MESSAGE_END();
- EMIT_SOUND_DYN2 (pEntity, CHAN_VOICE, "player/sprayer.wav", 1.0,
- ATTN_NORM, 0, 100);
- }
+ EMIT_SOUND_DYN2(pEntity, CHAN_VOICE, "player/sprayer.wav", 1.0,
+ ATTN_NORM, 0, 100);
+ }
}
// Give a radio message botty boy!
void
-UTIL_BotRadioMessage (cBot * pBot, int radio, char *arg1, char *arg2)
+UTIL_BotRadioMessage(cBot* pBot, int radio, char* arg1, char* arg2)
{
- // To be sure the console will only change when we MAY change.
- // The values will only be changed when console_nr is 0
- if (pBot->console_nr == 0)
- {
- switch (radio)
- {
- case 1:
- strcpy (pBot->arg1, "radio1");
- break;
- case 2:
- strcpy (pBot->arg1, "radio2");
- break;
- case 3:
- strcpy (pBot->arg1, "radio3");
- break;
- }
-
- strcpy (pBot->arg2, arg1);
- strcpy (pBot->arg3, arg2);
- pBot->console_nr = 1; // Begin message
- int iExtra = (100/pBot->ipCreateRadio);
- if (iExtra > 30) iExtra=30;
- pBot->fDoRadio = gpGlobals->time + iExtra;
- }
+ // To be sure the console will only change when we MAY change.
+ // The values will only be changed when console_nr is 0
+ if (pBot->console_nr == 0)
+ {
+ switch (radio)
+ {
+ case 1:
+ strcpy(pBot->arg1, "radio1");
+ break;
+ case 2:
+ strcpy(pBot->arg1, "radio2");
+ break;
+ case 3:
+ strcpy(pBot->arg1, "radio3");
+ break;
+ }
+
+ strcpy(pBot->arg2, arg1);
+ strcpy(pBot->arg3, arg2);
+ pBot->console_nr = 1; // Begin message
+ int iExtra = (100 / pBot->ipCreateRadio);
+ if (iExtra > 30) iExtra = 30;
+ pBot->fDoRadio = gpGlobals->time + iExtra;
+ }
}
//////////////////////////////////
// UTIL_getGrenadeType function // - Stefan
//////////////////////////////////
int
-UTIL_GetGrenadeType (edict_t * pEntity)
+UTIL_GetGrenadeType(edict_t* pEntity)
{
+ char model_name[32];
- char model_name[32];
-
- strcpy (model_name, STRING (pEntity->v.model));
+ strcpy(model_name, STRING(pEntity->v.model));
- if (strcmp (model_name, "models/w_hegrenade.mdl") == 0)
- return 1; // He grenade
- if (strcmp (model_name, "models/w_flashbang.mdl") == 0)
- return 2; // FlashBang
- if (strcmp (model_name, "models/w_smokegrenade.mdl") == 0)
- return 3; // SmokeGrenade
- if (strcmp (model_name, "models/w_c4.mdl") == 0)
- return 4; // C4 Explosive
-
- return 0;
+ if (strcmp(model_name, "models/w_hegrenade.mdl") == 0)
+ return 1; // He grenade
+ if (strcmp(model_name, "models/w_flashbang.mdl") == 0)
+ return 2; // FlashBang
+ if (strcmp(model_name, "models/w_smokegrenade.mdl") == 0)
+ return 3; // SmokeGrenade
+ if (strcmp(model_name, "models/w_c4.mdl") == 0)
+ return 4; // C4 Explosive
+ return 0;
}
// 2 functions from podbot source
unsigned short
-FixedUnsigned16 (float value, float scale)
+FixedUnsigned16(float value, float scale)
{
- int output;
+ int output;
- output = value * scale;
- if (output < 0)
- output = 0;
- if (output > 0xFFFF)
- output = 0xFFFF;
+ output = value * scale;
+ if (output < 0)
+ output = 0;
+ if (output > 0xFFFF)
+ output = 0xFFFF;
- return (unsigned short) output;
+ return (unsigned short)output;
}
short
-FixedSigned16 (float value, float scale)
+FixedSigned16(float value, float scale)
{
- int output;
+ int output;
- output = value * scale;
+ output = value * scale;
- if (output > 32767)
- output = 32767;
+ if (output > 32767)
+ output = 32767;
- if (output < -32768)
- output = -32768;
+ if (output < -32768)
+ output = -32768;
- return (short) output;
+ return (short)output;
}
// Using POD/SDK source to print nice messages on the client machine
void
-HUD_DrawString (int r, int g, int b, char *msg, edict_t * edict)
+HUD_DrawString(int r, int g, int b, char* msg, edict_t* edict)
{
- // FROM PODBOT SOURCE
- // Hacked together Version of HUD_DrawString
- MESSAGE_BEGIN (MSG_ONE, SVC_TEMPENTITY, NULL, edict);
- WRITE_BYTE (TE_TEXTMESSAGE);
- WRITE_BYTE (1);
- WRITE_SHORT (FixedSigned16 (-1, 1 << 13));
- WRITE_SHORT (FixedSigned16 (0, 1 << 13));
- WRITE_BYTE (2);
- WRITE_BYTE (r); //r
- WRITE_BYTE (g); //g
- WRITE_BYTE (b); //b
- WRITE_BYTE (0);
- WRITE_BYTE (255);
- WRITE_BYTE (255);
- WRITE_BYTE (255);
- WRITE_BYTE (200);
- WRITE_SHORT (FixedUnsigned16 (0.0078125, 1 << 8));
- WRITE_SHORT (FixedUnsigned16 (2, 1 << 8));
- WRITE_SHORT (FixedUnsigned16 (6, 1 << 8));
- WRITE_SHORT (FixedUnsigned16 (0.1, 1 << 8));
- WRITE_STRING ((const char *) &msg[0]);
- MESSAGE_END ();
+ // FROM PODBOT SOURCE
+ // Hacked together Version of HUD_DrawString
+ MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, edict);
+ WRITE_BYTE(TE_TEXTMESSAGE);
+ WRITE_BYTE(1);
+ WRITE_SHORT(FixedSigned16(-1, 1 << 13));
+ WRITE_SHORT(FixedSigned16(0, 1 << 13));
+ WRITE_BYTE(2);
+ WRITE_BYTE(r); //r
+ WRITE_BYTE(g); //g
+ WRITE_BYTE(b); //b
+ WRITE_BYTE(0);
+ WRITE_BYTE(255);
+ WRITE_BYTE(255);
+ WRITE_BYTE(255);
+ WRITE_BYTE(200);
+ WRITE_SHORT(FixedUnsigned16(0.0078125, 1 << 8));
+ WRITE_SHORT(FixedUnsigned16(2, 1 << 8));
+ WRITE_SHORT(FixedUnsigned16(6, 1 << 8));
+ WRITE_SHORT(FixedUnsigned16(0.1, 1 << 8));
+ WRITE_STRING((const char*)&msg[0]);
+ MESSAGE_END();
}
-
void
-UTIL_FixAngles (Vector * Angles)
+UTIL_FixAngles(Vector* Angles)
{
- if (Angles->x > 180.0)
- Angles->x -= 360.0;
- if (Angles->x < -180.0)
- Angles->x += 360.0;
- if (Angles->y > 180.0)
- Angles->y -= 360.0;
- if (Angles->y < -180.0)
- Angles->y += 360.0;
-
- Angles->z = 0.0;
+ if (Angles->x > 180.0)
+ Angles->x -= 360.0;
+ if (Angles->x < -180.0)
+ Angles->x += 360.0;
+ if (Angles->y > 180.0)
+ Angles->y -= 360.0;
+ if (Angles->y < -180.0)
+ Angles->y += 360.0;
+
+ Angles->z = 0.0;
}
// POD SAYING:
-void UTIL_SayTextBot( const char *pText,cBot *pBot)
-{
- if (gmsgSayText == 0)
- gmsgSayText = REG_USER_MSG ("SayText", -1);
-
+void UTIL_SayTextBot(const char* pText, cBot* pBot)
+{
+ if (gmsgSayText == 0)
+ gmsgSayText = REG_USER_MSG("SayText", -1);
+
char szTemp[160];
- char szName[BOT_NAME_LEN+1];
- int i=0;
-
- // clear out
- memset (szTemp, 0, sizeof (szTemp));
- memset (szName, 0, sizeof (szName));
+ char szName[BOT_NAME_LEN + 1];
+ int i = 0;
+
+ // clear out
+ memset(szTemp, 0, sizeof(szTemp));
+ memset(szName, 0, sizeof(szName));
// init
- szTemp[0]=2;
+ szTemp[0] = 2;
- int entind=ENTINDEX(pBot->pEdict);
+ int entind = ENTINDEX(pBot->pEdict);
- if(IsAlive(pBot->pEdict))
+ if (IsAlive(pBot->pEdict))
{
- strcpy(szName,pBot->name);
+ strcpy(szName, pBot->name);
for (i = 1; i <= gpGlobals->maxClients; i++)
- {
- edict_t *pPlayer = INDEXENT (i);
+ {
+ edict_t* pPlayer = INDEXENT(i);
// valid
if (pPlayer)
if (IsAlive(pPlayer)) // alive
- {
- MESSAGE_BEGIN( MSG_ONE, gmsgSayText,NULL,pPlayer);
+ {
+ MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, pPlayer);
WRITE_BYTE(entind);
- sprintf(&szTemp[1],"%s : %s",szName,pText);
+ sprintf(&szTemp[1], "%s : %s", szName, pText);
WRITE_STRING(&szTemp[0]);
MESSAGE_END();
}
@@ -1020,36 +1013,34 @@ void UTIL_SayTextBot( const char *pText,cBot *pBot)
}
else
{
- strcpy(szName,pBot->name);
+ strcpy(szName, pBot->name);
for (i = 1; i <= gpGlobals->maxClients; i++)
{
- edict_t *pPlayer = INDEXENT (i);
+ edict_t* pPlayer = INDEXENT(i);
if (pPlayer)
if (!IsAlive(pPlayer))
{
- MESSAGE_BEGIN( MSG_ONE, gmsgSayText,NULL,pPlayer);
+ MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, pPlayer);
WRITE_BYTE(entind);
- sprintf(&szTemp[1],"*DEAD*%s : %s",szName,pText);
+ sprintf(&szTemp[1], "*DEAD*%s : %s", szName, pText);
WRITE_STRING(&szTemp[0]);
MESSAGE_END();
}
}
}
-
// pass through on ChatEngine (not always)
- if (RANDOM_LONG(0,100) < 90)
+ if (RANDOM_LONG(0, 100) < 90)
{
char chSentence[80];
- memset (chSentence, 0, sizeof (chSentence));
-
+ memset(chSentence, 0, sizeof(chSentence));
+
// copy pText to chSentence
strcpy(chSentence, pText);
// pass through
- ChatEngine.set_sentence(pBot->name,chSentence);
+ ChatEngine.set_sentence(pBot->name, chSentence);
}
-
}
// $Log: util.cpp,v $
@@ -1063,5 +1054,4 @@ void UTIL_SayTextBot( const char *pText,cBot *pBot)
// - added two other utilities DrawNodes & DumpNodes
// - updated README file
// - fixed compilation warnings (thanks dstruct2k)
-//
-
+//
\ No newline at end of file
diff --git a/Bsp2Rbn/world.cpp b/Bsp2Rbn/world.cpp
index ac46011..d0bbc06 100644
--- a/Bsp2Rbn/world.cpp
+++ b/Bsp2Rbn/world.cpp
@@ -15,7 +15,7 @@
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License for more details at:
// http://www.gnu.org/copyleft/gpl.html
@@ -27,7 +27,6 @@
#include
#include
-
#include "cmdlib.h"
#include "mathlib.h"
#include "bspfile.h"
@@ -39,144 +38,140 @@ World::World(void)
{
}
-
World::~World(void)
{
- FreeWorld();
+ FreeWorld();
}
-
void World::FreeWorld(void)
{
- FreeEntities();
-
- if (dmodels)
- {
- free(dmodels);
- dmodels = NULL;
- nummodels = 0;
- }
-
- if (dvisdata)
- {
- free(dvisdata);
- dvisdata = NULL;
- visdatasize = 0;
- }
-
- if (dlightdata)
- {
- free(dlightdata);
- dlightdata = NULL;
- lightdatasize = 0;
- }
-
- if (dtexdata)
- {
- free(dtexdata);
- dtexdata = NULL;
- texdatasize = 0;
- }
-
- if (dentdata)
- {
- free(dentdata);
- dentdata = NULL;
- entdatasize = 0;
- }
-
- if (dleafs)
- {
- free(dleafs);
- dleafs = NULL;
- numleafs = 0;
- }
-
- if (dplanes)
- {
- free(dplanes);
- dplanes = NULL;
- numplanes = 0;
- }
-
- if (dvertexes)
- {
- free(dvertexes);
- dvertexes = NULL;
- numvertexes = 0;
- }
-
- if (dnodes)
- {
- free(dnodes);
- dnodes = NULL;
- numnodes = 0;
- }
-
- if (texinfo)
- {
- free(texinfo);
- texinfo = NULL;
- numtexinfo = 0;
- }
-
- if (dfaces)
- {
- free(dfaces);
- dfaces = NULL;
- numfaces = 0;
- }
-
- if (dclipnodes)
- {
- free(dclipnodes);
- dclipnodes = NULL;
- numclipnodes = 0;
- }
-
- if (dedges)
- {
- free(dedges);
- dedges = NULL;
- numedges = 0;
- }
-
- if (dmarksurfaces)
- {
- free(dmarksurfaces);
- dmarksurfaces = NULL;
- nummarksurfaces = 0;
- }
-
- if (dsurfedges)
- {
- free(dsurfedges);
- dsurfedges = NULL;
- numsurfedges = 0;
- }
+ FreeEntities();
+
+ if (dmodels)
+ {
+ free(dmodels);
+ dmodels = NULL;
+ nummodels = 0;
+ }
+
+ if (dvisdata)
+ {
+ free(dvisdata);
+ dvisdata = NULL;
+ visdatasize = 0;
+ }
+
+ if (dlightdata)
+ {
+ free(dlightdata);
+ dlightdata = NULL;
+ lightdatasize = 0;
+ }
+
+ if (dtexdata)
+ {
+ free(dtexdata);
+ dtexdata = NULL;
+ texdatasize = 0;
+ }
+
+ if (dentdata)
+ {
+ free(dentdata);
+ dentdata = NULL;
+ entdatasize = 0;
+ }
+
+ if (dleafs)
+ {
+ free(dleafs);
+ dleafs = NULL;
+ numleafs = 0;
+ }
+
+ if (dplanes)
+ {
+ free(dplanes);
+ dplanes = NULL;
+ numplanes = 0;
+ }
+
+ if (dvertexes)
+ {
+ free(dvertexes);
+ dvertexes = NULL;
+ numvertexes = 0;
+ }
+
+ if (dnodes)
+ {
+ free(dnodes);
+ dnodes = NULL;
+ numnodes = 0;
+ }
+
+ if (texinfo)
+ {
+ free(texinfo);
+ texinfo = NULL;
+ numtexinfo = 0;
+ }
+
+ if (dfaces)
+ {
+ free(dfaces);
+ dfaces = NULL;
+ numfaces = 0;
+ }
+
+ if (dclipnodes)
+ {
+ free(dclipnodes);
+ dclipnodes = NULL;
+ numclipnodes = 0;
+ }
+
+ if (dedges)
+ {
+ free(dedges);
+ dedges = NULL;
+ numedges = 0;
+ }
+
+ if (dmarksurfaces)
+ {
+ free(dmarksurfaces);
+ dmarksurfaces = NULL;
+ nummarksurfaces = 0;
+ }
+
+ if (dsurfedges)
+ {
+ free(dsurfedges);
+ dsurfedges = NULL;
+ numsurfedges = 0;
+ }
}
-
-void World::LoadBSP(char *bspfile)
+void World::LoadBSP(char* bspfile)
{
- char bsp_filename[256];
- char pathname[256];
- bool bsp_found;
- int index, mod_index;
- char modname[256];
- int len;
-
- bsp_found = FALSE;
+ char bsp_filename[256];
+ char pathname[256];
+ bool bsp_found;
+ int index, mod_index;
+ char modname[256];
+ int len;
- strcpy(bspname, bspfile);
+ bsp_found = FALSE;
- if (FileTime(bspname) != -1) // does the specified file exist?
- LoadBSPFile(bspname);
- else
- fprintf(stderr,"Cannot load file %s\n",bspname) ;
+ strcpy(bspname, bspfile);
- ParseEntities();
+ if (FileTime(bspname) != -1) // does the specified file exist?
+ LoadBSPFile(bspname);
+ else
+ fprintf(stderr, "Cannot load file %s\n", bspname);
- LoadEntVars();
-}
+ ParseEntities();
+ LoadEntVars();
+}
\ No newline at end of file
diff --git a/Bsp2Rbn/world.h b/Bsp2Rbn/world.h
index 18233b2..9b68ae8 100644
--- a/Bsp2Rbn/world.h
+++ b/Bsp2Rbn/world.h
@@ -15,7 +15,7 @@
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License for more details at:
// http://www.gnu.org/copyleft/gpl.html
@@ -31,18 +31,17 @@
#ifndef WORLD_H
#define WORLD_H
-
class World
{
- public:
+public:
- char bspname[256]; // name of the currently loaded BSP file
+ char bspname[256]; // name of the currently loaded BSP file
- World(void);
- ~World(void);
+ World(void);
+ ~World(void);
- void FreeWorld(void);
- void LoadBSP(char *bspfile);
+ void FreeWorld(void);
+ void LoadBSP(char* bspfile);
};
#ifndef __linux__
@@ -50,4 +49,3 @@ BOOL CenterWindow(HWND hWnd);
#endif
#endif
-
diff --git a/ChatEngine.cpp b/ChatEngine.cpp
index 984113d..36ba7b6 100644
--- a/ChatEngine.cpp
+++ b/ChatEngine.cpp
@@ -1,3 +1,5 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check it.
+// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
/**
* RealBot : Artificial Intelligence
* Version : Work In Progress
@@ -6,7 +8,7 @@
**
* DISCLAIMER
*
- * History, Information & Credits:
+ * History, Information & Credits:
* RealBot is based partially upon the HPB-Bot Template #3 by Botman
* Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
* Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
@@ -18,9 +20,9 @@
*
* Pierre Marie Baty
* Count-Floyd
- *
+ *
* !! BOTS-UNITED FOREVER !!
- *
+ *
* This project is open-source, it is protected under the GPL license;
* By using this source-code you agree that you will ALWAYS release the
* source-code with your project.
@@ -28,12 +30,15 @@
**/
// Chatting Engine
-#include
-#include
+#include
+#include
// Some tests by EVYNCKE
#include
+#include
#include
-#include
+#include
+#include
+
#include
#include
@@ -48,30 +53,48 @@
#include "ChatEngine.h"
-extern edict_t *pHostEdict;
+extern edict_t* pHostEdict;
extern cGame Game;
extern cBot bots[32];
+namespace {
+ edict_t* findPlayerEdictByName(const char* playerName) {
+ if (!playerName || *playerName == '\0') {
+ return nullptr;
+ }
+
+ for (int i = 1; i <= gpGlobals->maxClients; i++) {
+ edict_t* pPlayer = INDEXENT(i);
+ if (pPlayer && !pPlayer->free) {
+ if (std::strcmp(STRING(pPlayer->v.netname), playerName) == 0) {
+ return pPlayer;
+ }
+ }
+ }
+ return nullptr;
+ }
+}
+
// initialize all
-void
-cChatEngine::init() {
+void cChatEngine::init() {
// clear all blocks
- for (int iB = 0; iB < MAX_BLOCKS; iB++) {
- for (int iBs = 0; iBs < 50; iBs++)
- ReplyBlock[iB].sentence[iBs][0] = '\0';
+ for (tReplyBlock& iB : ReplyBlock)
+ {
+ for (char(&iBs)[128] : iB.sentence)
+ iBs[0] = '\0';
- for (int iBw = 0; iBw < 10; iBw++)
- ReplyBlock[iB].word[iBw][0] = '\0';
+ for (char(&iBw)[25] : iB.word)
+ iBw[0] = '\0';
- ReplyBlock[iB].bUsed = false;
+ iB.bUsed = false;
}
iLastBlock = -1;
iLastSentence = -1;
// init sentence
- memset(sentence, 0, sizeof(sentence));
- memset(sender, 0, sizeof(sender));
+ std::memset(sentence, 0, sizeof(sentence));
+ std::memset(sender, 0, sizeof(sender));
}
// load
@@ -84,7 +107,7 @@ void cChatEngine::initAndload() {
// think
void cChatEngine::think() {
- if (fThinkTimer + 1.0 > gpGlobals->time) return; // not time yet to think
+ if (fThinkTimer + 1.0f > gpGlobals->time) return; // not time yet to think
// decrease over time to avoid flooding
if (Game.iProducedSentences > 1) {
@@ -94,47 +117,15 @@ void cChatEngine::think() {
// if no sender is set, do nothing
if (sender[0] == '\0') return;
- // 29/08/2019 Stefan: by using string compare on the name of the sender (ie sender[] is the name) we retrieve
- // the edict pointer
- edict_t *pSender = NULL;
- int i;
- for (i = 1; i <= gpGlobals->maxClients; i++) {
- edict_t *pPlayer = INDEXENT(i);
-
- if (pPlayer && (!pPlayer->free)) {
- char name[30], name2[30];
- // clear
- memset(name, 0, sizeof(name));
- memset(name2, 0, sizeof(name2));
-
- // copy
- strcpy(name, STRING(pPlayer->v.netname));
- strcpy(name2, sender);
-
- if (strcmp(name, name2) == 0) {
- pSender = pPlayer;
- break;
- }
- }
- }
- // Edict pointer established
+ edict_t* pSender = findPlayerEdictByName(sender);
// Scan the message so we know in what block we should be to reply:
- char word[20];
- memset(word, 0, sizeof(word));
-
- int c = 0;
- int wc = 0;
-
- int sentenceLength = strlen(sentence);
+ std::string_view sentence_sv(sentence);
- // When length is not valid, get out.
- // 29/08/2019: Stefan, so let me get this. We declare the sentence to be max 128 chars, but then we still could end up with a longer one?
- // how did we allow for this to happen?
- if (sentenceLength == 0 || sentenceLength >= (MAX_SENTENCE_LENGTH-1)) {
+ if (sentence_sv.empty() || sentence_sv.length() >= MAX_SENTENCE_LENGTH - 1) {
// clear out sentence and sender
- memset(sentence, 0, sizeof(sentence));
- memset(sender, 0, sizeof(sender));
+ std::memset(sentence, 0, sizeof(sentence));
+ std::memset(sender, 0, sizeof(sender));
// reset timer
fThinkTimer = gpGlobals->time;
@@ -142,79 +133,24 @@ void cChatEngine::think() {
return;
}
- int WordBlockScore[MAX_BLOCKS];
+ std::vector WordBlockScore(MAX_BLOCKS, 0);
- // Init, none of the block has a score yet (set to -1)
- for (int wbs = 0; wbs < MAX_BLOCKS; wbs++) {
- WordBlockScore[wbs] = -1;
- }
-
- // loop over the sentence character by character
- while (c < sentenceLength) {
- // protection matters:
- // Stefan: this is weird, this can never happen?!
- if (c > sentenceLength)
- break;
-
- if (c < 0)
- break;
- // End of protection matters
-
- // Step: Check character to identify the end of a word.
- if (sentence[c] == ' ' || sentence[c] == '\n' ||
- sentence[c] == '.' || sentence[c] == '?' ||
- sentence[c] == '!' || c == sentenceLength) {
- // Now find the word and add up scors on the proper score blocks.
-
- if (c == sentenceLength)
- word[wc] = sentence[c];
-
- // not a good word (too small)
- if (strlen(word) <= 0) {
- //SERVER_PRINT("This is not a good word!\n");
- } else {
- for (int iB = 0; iB < MAX_BLOCKS; iB++) {
- if (ReplyBlock[iB].bUsed) {
- for (int iBw = 0; iBw < 10; iBw++) {
- // skip any word in the reply block that is not valid
- if (ReplyBlock[iB].word[iBw][0] == '\0')
- continue; // not filled in
-
- if (strlen(ReplyBlock[iB].word[iBw]) <= 0)
- continue; // not long enough (a space?)
-
- // 03/07/04
- // add score to matching word (evy: ignoring case)
- if (strcmpi(ReplyBlock[iB].word[iBw], word) == 0)
- WordBlockScore[iB]++;
- } // all words in this block
- } // any used block
- } // for all blocks
- } // good word
-
- // clear out entire word.
- //for (int cw=0; cw < 20; cw++)
- // word[cw] = '\0';
- memset(word, 0, sizeof(word));
-
- wc = 0; // reset WC position (start writing 'word[WC]' at 0 again)
- c++; // next position in sentence
- continue; // go to top again.
+ std::stringstream ss(sentence);
+ std::string word_str;
+ while (ss >> word_str) {
+ for (int iB = 0; iB < MAX_BLOCKS; iB++) {
+ if (ReplyBlock[iB].bUsed) {
+ for (const char (&iBw)[25] : ReplyBlock[iB].word) {
+ if (iBw[0] != '\0' && word_str == iBw) {
+ WordBlockScore[iB]++;
+ }
+ }
+ }
}
- // when we end up here, we are still reading a 'non finishing word' character.
- // we will fill that in word[wc]. Then add up wc and c, until we find a character
- // that marks the end of a word again.
-
- // fill in the word:
- word[wc] = sentence[c];
-
- // add up.
- c++;
- wc++;
- } // end of loop
+ }
// now loop through all blocks and find the one with the most score:
- int iMaxScore = -1;
+ int iMaxScore = 0;
int iTheBlock = -1;
// for all blocks
@@ -232,34 +168,28 @@ void cChatEngine::think() {
int iMax = -1;
// now choose a sentence to reply with
- for (int iS = 0; iS < 50; iS++) {
+ for (const char(&iS)[128] : ReplyBlock[iTheBlock].sentence)
+ {
// Find max sentences of this reply block
- if (ReplyBlock[iTheBlock].sentence[iS][0] != '\0')
+ if (iS[0] != '\0')
iMax++;
}
// loop through all bots:
for (int i = 1; i <= gpGlobals->maxClients; i++) {
- edict_t *pPlayer = INDEXENT(i);
+ edict_t* pPlayer = INDEXENT(i);
// skip invalid players and skip self (i.e. this bot)
- if ((pPlayer) && (!pPlayer->free) && pSender != pPlayer) {
-
- // only reply to the living when alive, and otherwise
- bool bSenderAlive = false;
- bool bPlayerAlive = false;
-
- bSenderAlive = IsAlive(pSender); // CRASH : it sometimes crashes here
- bPlayerAlive = IsAlive(pPlayer);
-
- if (bSenderAlive != bPlayerAlive)
+ if (pPlayer && !pPlayer->free && pSender != pPlayer)
+ {
+ if (!IsAlive(pSender) || !IsAlive(pPlayer))
continue;
- cBot *pBotPointer = UTIL_GetBotPointer(pPlayer);
+ cBot* pBotPointer = UTIL_GetBotPointer(pPlayer);
- if (pBotPointer != NULL)
+ if (pBotPointer != nullptr)
if (RANDOM_LONG(0, 100) <
- (pBotPointer->ipChatRate + 25)) {
+ pBotPointer->ipChatRate + 25) {
// When we have at least 1 sentence...
if (iMax > -1) {
// choose randomly a reply
@@ -269,93 +199,31 @@ void cChatEngine::think() {
the_c == iLastSentence) {
// when this is the same, avoid it. Try to change again
if (iMax > 0)
- the_c++;
+ the_c = (the_c + 1) % (iMax + 1);
else
continue; // do not reply double
-
- if (the_c > iMax)
- the_c = 0;
}
// the_c is choosen, it is the sentence we reply with.
// do a check if its valid:
if (ReplyBlock[iTheBlock].
- sentence[the_c][0] != '\0') {
+ sentence[the_c][0] != '\0') {
// chSentence is eventually what the bot will say.
char chSentence[128];
- char temp[80];
-
- memset(chSentence, 0, sizeof(chSentence));
- memset(temp, 0, sizeof(temp));
-
- // get character position
- char *name_pos =
- strstr(ReplyBlock[iTheBlock].
- sentence[the_c], "%n");
-
- // when name_pos var is found, fill it in.
- if (name_pos != NULL) {
- // when name is in this one:
- int name_offset =
- name_pos -
- ReplyBlock[iTheBlock].sentence[the_c];
- name_offset--;
-
- // copy every character till name_offset
- int nC;
- for (nC = 0; nC < name_offset; nC++) {
- //chSentence[nC] = ReplyBlock[iTheBlock].sentence[the_c][nC];
- temp[nC] =
- ReplyBlock[iTheBlock].
- sentence[the_c][nC];
- }
-
- temp[nC] = ' ';
-
- // copy senders name to chSentence
- strcat(temp, sender);
-
- // From here us 'tc' to keep track of chSentence and use
- // nC to keep reading from ReplyBlock
- int tc = nC;
-
- // Skip %n part in ReplyBlock
- nC = name_offset + 3;
-
- // we just copied a name to chSentence
- // set our cursor after the name now (name length + 1)
- tc = strlen(temp);
-
- // now finish the sentence
- // get entire length of ReplyBlock and go until we reach the end
- int length =
- strlen(ReplyBlock[iTheBlock].
- sentence[the_c]);
-
-
- // for every nC , read character from ReplyBlock
- for (; nC <= length; nC++) {
- // ... and copy it into chSentence
- temp[tc] =
- ReplyBlock[iTheBlock].
- sentence[the_c][nC];
- //char tmsg[80];
- //sprintf(tmsg,"Copying char %c , tc = %d, nC = %d\n", temp[tc], tc, nC);
- //SERVER_PRINT(tmsg);
-
- tc++; // add up tc.
- }
-
- // terminate
- temp[tc] = '\n';
-
- sprintf(chSentence, "%s \n", temp);
+ std::string_view reply_template(ReplyBlock[iTheBlock].sentence[the_c]);
+ size_t name_pos = reply_template.find("%n");
+
+ if (name_pos != std::string_view::npos) {
+ std::string final_sentence = std::string(reply_template.substr(0, name_pos));
+ final_sentence += sender;
+ final_sentence += reply_template.substr(name_pos + 2);
+ snprintf(chSentence, sizeof(chSentence), "%s \n", final_sentence.c_str());
+ }
+ // when no name pos is found, we just copy the string and say that (works ok)
+ else {
+ snprintf(chSentence, sizeof(chSentence), "%s \n",
+ ReplyBlock[iTheBlock].sentence[the_c]);
}
- // when no name pos is found, we just copy the string and say that (works ok)
- else
- sprintf(chSentence, "%s \n",
- ReplyBlock[iTheBlock].
- sentence[the_c]);
// reply:
pBotPointer->PrepareChat(chSentence);
@@ -374,41 +242,59 @@ void cChatEngine::think() {
}
// clear sentence and such
- memset(sentence, 0, sizeof(sentence));
- memset(sender, 0, sizeof(sender));
+ std::memset(sentence, 0, sizeof(sentence));
+ std::memset(sender, 0, sizeof(sender));
- fThinkTimer = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5);
+ fThinkTimer = gpGlobals->time + RANDOM_FLOAT(0.0f, 0.5f);
}
-//
-void cChatEngine::set_sentence(char csender[30], char csentence[128]) {
-
- if (sender[0] == ' ' || sender[0] == '\0') {
- // SERVER_PRINT("Sender & sentence set.\nSender=");
- // SERVER_PRINT(csender);
- // SERVER_PRINT("\nSentence=");
- // SERVER_PRINT(csentence);
- // SERVER_PRINT("--\n");
-
- strcpy(sender, csender);
-#ifdef _WIN32
-
- _strupr(csentence);
- // #elseif did not compile in MSVC - stefan (26/04/04)
-#else
- //for linux by ok:
- //further changed back by evyncke as these are normal string not CString
- //Hence, hardcoding the strupr inline...
- char *pString;
- pString = csentence;
- while (*pString) {
- *pString = toupper(*pString);
- pString++;
+void cChatEngine::handle_sentence() {
+ // Define a constant for the chat rate threshold
+ constexpr int CHAT_RATE_THRESHOLD = 25;
+
+ // Check if there is a sentence to process
+ if (sentence[0] == '\0') {
+ return;
+ }
+
+ // Loop through all clients
+ for (int i = 1; i <= gpGlobals->maxClients; i++) {
+ edict_t* pPlayer = INDEXENT(i);
+
+ // Skip invalid players
+ if (pPlayer && !pPlayer->free) {
+ cBot* pBotPointer = UTIL_GetBotPointer(pPlayer);
+
+ // Check if bot pointer is valid and decide to prepare chat
+ if (pBotPointer != nullptr && RANDOM_LONG(0, 100) < pBotPointer->ipChatRate + CHAT_RATE_THRESHOLD) {
+ pBotPointer->PrepareChat(sentence);
+ }
}
-#endif
- strcpy(sentence, csentence);
}
+
+ // Clear sentence and sender buffers
+ std::memset(sentence, 0, sizeof(sentence));
+ std::memset(sender, 0, sizeof(sender));
+
+ // Set the think timer
+ fThinkTimer = gpGlobals->time + RANDOM_FLOAT(0.0f, 0.5f);
+}
+
+
+void cChatEngine::set_sentence(char csender[MAX_NAME_LENGTH], char csentence[MAX_SENTENCE_LENGTH]) {
+ if (sender[0] == ' ' || sender[0] == '\0') {
+ strncpy(sender, csender, sizeof(sender) - 1);
+ sender[sizeof(sender) - 1] = '\0';
+
+#ifdef _WIN32
+ _strupr(csentence);
+#else
+ std::transform(csentence, csentence + std::strlen(csentence), csentence, ::toupper);
+#endif
+ strncpy(sentence, csentence, sizeof(sentence) - 1);
+ sentence[sizeof(sentence) - 1] = '\0';
+ }
}
diff --git a/ChatEngine.h b/ChatEngine.h
index 227e0bd..8f5884d 100644
--- a/ChatEngine.h
+++ b/ChatEngine.h
@@ -28,10 +28,14 @@
**/
// Chatting Engine
-#define MAX_BLOCKS 100
-#define BLOCK_DEATHS MAX_BLOCKS-1
+#ifndef CHATENGINE_H
+#define CHATENGINE_H
-static const int MAX_SENTENCE_LENGTH = 128;
+constexpr int MAX_BLOCKS = 100;
+
+#define BLOCK_DEATHS (MAX_BLOCKS-1)
+
+static constexpr int MAX_SENTENCE_LENGTH = 128;
// Reply block
typedef struct {
// words, hinting that in this block a logical sentence will be to reply with
@@ -59,8 +63,10 @@ class cChatEngine {
void think(); // make the chat engine think
// add sentence from any player/bot into memory to handle
- void set_sentence(char csender[30], char csentence[MAX_SENTENCE_LENGTH]);
+ void set_sentence(char csender[32], char csentence[MAX_SENTENCE_LENGTH]);
// handles a sentence, decides to reply on it or not.
void handle_sentence();
};
+
+#endif // CHATENGINE_H
\ No newline at end of file
diff --git a/IniParser.cpp b/IniParser.cpp
index 0f4bc4c..f65396c 100644
--- a/IniParser.cpp
+++ b/IniParser.cpp
@@ -1,3 +1,5 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check it.
+// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
/**
* RealBot : Artificial Intelligence
* Version : Work In Progress
@@ -6,7 +8,7 @@
**
* DISCLAIMER
*
- * History, Information & Credits:
+ * History, Information & Credits:
* RealBot is based partially upon the HPB-Bot Template #3 by Botman
* Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
* Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
@@ -18,21 +20,22 @@
*
* Pierre Marie Baty
* Count-Floyd
- *
+ *
* !! BOTS-UNITED FOREVER !!
- *
+ *
* This project is open-source, it is protected under the GPL license;
* By using this source-code you agree that you will ALWAYS release the
* source-code with your project.
*
**/
-/**
- * INI PARSER
- * COPYRIGHTED BY STEFAN HENDRIKS (C) 2003-2004
- **/
+ /**
+ * INI PARSER
+ * COPYRIGHTED BY STEFAN HENDRIKS (C) 2003-2004
+ **/
-#include
+#include
+#include
#include
#include
#include
@@ -46,1023 +49,907 @@
#include "NodeMachine.h"
#include "ChatEngine.h"
-#include
+#include
+#include
+#include
extern int mod_id;
-extern edict_t *pHostEdict;
+extern edict_t* pHostEdict;
extern cNodeMachine NodeMachine;
extern int m_spriteTexture;
extern cGame Game;
extern cChatEngine ChatEngine;
-
// Reads out INPUT , will check for a [ at [0] and then checks till ], it will fill section[]
// with the chars in between. So : [MAP] -> section = 'MAP'. Use function INI_SectionType(..)
// to get the correct ID for that.
void INI_Section(char input[80], char section[30]) {
-
- int pos = 0;
- int end_pos = -1;
-
- // clear out entire string
- for (int i = 0; i < 30; i++)
- section[i] = '\0';
-
- // check if the first character is a '['
- if (input[0] == '[') {
- pos = 1; // Begin at character 1
-
- while (pos < 79) {
- if (input[pos] == ']') {
- end_pos = pos - 1;
- break;
- }
- pos++;
- }
-
- if (end_pos > 1 && end_pos < 29) {
- for (int wc = 0; wc < end_pos; wc++)
- section[wc] = input[wc + 1];
-
- section[end_pos] = '\0'; // terminate string
- }
- }
-
+ int end_pos = -1;
+
+ // clear out entire string
+ for (int i = 0; i < 30; i++)
+ section[i] = '\0';
+
+ // check if the first character is a '['
+ if (input[0] == '[') {
+ int pos = 1; // Begin at character 1
+
+ while (pos < 79) {
+ if (input[pos] == ']') {
+ end_pos = pos - 1;
+ break;
+ }
+ pos++;
+ }
+
+ if (end_pos > 1 && end_pos < 29) {
+ for (int wc = 0; wc < end_pos; wc++)
+ section[wc] = input[wc + 1];
+
+ section[end_pos] = '\0'; // terminate string
+ }
+ }
}
// Reads out INPUT and will check for an '=' Everything at the left of the
// '=' IS a word and will be put in 'word[]'. Use function INI_WordType(char word[25]) to get
// the correct ID tag.
void INI_Word(char input[80], char word[25]) {
- int pos = 0;
- int word_pos = -1;
-
- // clear out entire string
- for (int i = 0; i < 25; i++)
- word[i] = '\0';
-
- while (pos < 79) {
- if (input[pos] == '=') {
- word_pos = pos;
- break;
- }
- pos++;
- }
-
- if (word_pos > -1 && word_pos < 23) {
- for (int wc = 0; wc < word_pos; wc++)
- word[wc] = input[wc];
-
- word[word_pos] = '\0'; // terminate string
- }
+ int pos = 0;
+ int word_pos = -1;
+
+ // clear out entire string
+ for (int i = 0; i < 25; i++)
+ word[i] = '\0';
+
+ while (pos < 79) {
+ if (input[pos] == '=') {
+ word_pos = pos;
+ break;
+ }
+ pos++;
+ }
+
+ if (word_pos > -1 && word_pos < 23) {
+ for (int wc = 0; wc < word_pos; wc++)
+ word[wc] = input[wc];
+
+ word[word_pos] = '\0'; // terminate string
+ }
}
// Reads out word[], does a string compare and returns type id
int INI_WordType(char word[25], int section) {
- if (strlen(word) > 0) {
-
- if (strcmp(word, "Word") == 0)
- return WORD_WORD;
- if (strcmp(word, "Sentence") == 0)
- return WORD_SENTENCE;
-
-
- if (strcmp(word, "X") == 0)
- return WORD_AREAX;
- if (strcmp(word, "Y") == 0)
- return WORD_AREAY;
- if (strcmp(word, "Z") == 0)
- return WORD_AREAZ;
-
- // ------ personality stuff ------
- if (strcmp(word, "PrimaryWeapon") == 0)
- return WORD_PRIWEAPON;
-
- if (strcmp(word, "SecondaryWeapon") == 0)
- return WORD_SECWEAPON;
-
- if (strcmp(word, "SaveForWeapon") == 0)
- return WORD_SAVEFORWEAP;
-
- if (strcmp(word, "Grenade") == 0)
- return WORD_GRENADE;
-
- if (strcmp(word, "FlashBang") == 0)
- return WORD_FLASHBANG;
-
- if (strcmp(word, "SmokeGrenade") == 0)
- return WORD_SMOKEGREN;
-
- if (strcmp(word, "DefuseKit") == 0)
- return WORD_DEFUSEKIT;
-
- if (strcmp(word, "Armour") == 0)
- return WORD_ARMOUR;
-
- // ---- skill
-
- if (strcmp(word, "XOffset") == 0)
- return WORD_XOFFSET;
-
- if (strcmp(word, "YOffset") == 0)
- return WORD_YOFFSET;
-
- if (strcmp(word, "ZOffset") == 0)
- return WORD_ZOFFSET;
-
- if (strcmp(word, "BotSkill") == 0)
- return WORD_BOTSKILL;
-
- if (strcmp(word, "MaxReactionTime") == 0)
- return WORD_MAXREACTTIME;
-
- if (strcmp(word, "MinReactionTime") == 0)
- return WORD_MINREACTTIME;
-
- if (strcmp(word, "Turnspeed") == 0)
- return WORD_TURNSPEED;
-
- // ---- Game
- if (strcmp(word, "Hostage") == 0)
- return WORD_HOSTAGERATE;
-
- if (strcmp(word, "BompSpot") == 0)
- return WORD_BOMBSPOTRATE;
-
- if (strcmp(word, "Random") == 0)
- return WORD_RANDOMRATE;
- if (strcmp(word, "DroppedBomb") == 0)
- return WORD_DROPPEDBOMB;
-
- // ---- Radio
- if (strcmp(word, "Reply") == 0)
- return WORD_REPLYRADIO;
-
- if (strcmp(word, "Create") == 0)
- return WORD_CREATERADIO;
-
- // ---- Team
- if (strcmp(word, "HelpTeammate") == 0)
- return WORD_HELPTEAM;
-
- // ---- person
- if (strcmp(word, "WalkWithKnife") == 0)
- return WORD_WALKKNIFE;
- if (strcmp(word, "FearRate") == 0)
- return WORD_FEARRATE;
- if (strcmp(word, "HearRate") == 0)
- return WORD_HEARRATE;
- if (strcmp(word, "ChatRate") == 0)
- return WORD_CHATRATE;
-
- if (strcmp(word, "CampRate") == 0)
- return WORD_CAMPRATE;
-
- // ------ buy table stuff -------
- if (strcmp(word, "Price") == 0)
- return WORD_PRICE;
-
- if (strcmp(word, "Priority") == 0)
- return WORD_PRIORITY;
-
- if (strcmp(word, "Ammo1Index") == 0)
- return WORD_INDEX1;
-
- if (strcmp(word, "Ammo2Index") == 0)
- return WORD_INDEX2;
-
- if (strcmp(word, "Ammo1Max") == 0)
- return WORD_MAXAMMO1;
-
- if (strcmp(word, "Ammo2Max") == 0)
- return WORD_MAXAMMO2;
-
- }
-
- return WORD_NONE;
+ if (word[0] == '\0') {
+ return WORD_NONE;
+ }
+
+ static const std::unordered_map wordMap = {
+ {"Word", WORD_WORD},
+ {"Sentence", WORD_SENTENCE},
+ {"X", WORD_AREAX},
+ {"Y", WORD_AREAY},
+ {"Z", WORD_AREAZ},
+ {"PrimaryWeapon", WORD_PRIWEAPON},
+ {"SecondaryWeapon", WORD_SECWEAPON},
+ {"SaveForWeapon", WORD_SAVEFORWEAP},
+ {"Grenade", WORD_GRENADE},
+ {"FlashBang", WORD_FLASHBANG},
+ {"SmokeGrenade", WORD_SMOKEGREN},
+ {"DefuseKit", WORD_DEFUSEKIT},
+ {"Armour", WORD_ARMOUR},
+ {"XOffset", WORD_XOFFSET},
+ {"YOffset", WORD_YOFFSET},
+ {"ZOffset", WORD_ZOFFSET},
+ {"BotSkill", WORD_BOTSKILL},
+ {"MaxReactionTime", WORD_MAXREACTTIME},
+ {"MinReactionTime", WORD_MINREACTTIME},
+ {"Turnspeed", WORD_TURNSPEED},
+ {"Hostage", WORD_HOSTAGERATE},
+ {"BompSpot", WORD_BOMBSPOTRATE},
+ {"Random", WORD_RANDOMRATE},
+ {"DroppedBomb", WORD_DROPPEDBOMB},
+ {"Reply", WORD_REPLYRADIO},
+ {"Create", WORD_CREATERADIO},
+ {"HelpTeammate", WORD_HELPTEAM},
+ {"WalkWithKnife", WORD_WALKKNIFE},
+ {"FearRate", WORD_FEARRATE},
+ {"HearRate", WORD_HEARRATE},
+ {"ChatRate", WORD_CHATRATE},
+ {"CampRate", WORD_CAMPRATE},
+ {"Price", WORD_PRICE},
+ {"Priority", WORD_PRIORITY},
+ {"Ammo1Index", WORD_INDEX1},
+ {"Ammo2Index", WORD_INDEX2},
+ {"Ammo1Max", WORD_MAXAMMO1},
+ {"Ammo2Max", WORD_MAXAMMO2}
+ };
+
+ if (const std::unordered_map::const_iterator it = wordMap.find(word); it != wordMap.end()) {
+ return it->second;
+ }
+
+ return WORD_NONE;
}
// Reads out an entire sentence and returns it
-void INI_Sentence(FILE * f, char result[80]) {
-
- char ch;
- int pos = 0;
-
- // clear out entire string
- for (int i = 0; i < 80; i++)
- result[i] = '\0';
-
- while ((feof(f) == 0) && ((ch = fgetc(f)) != '\n')) {
- result[pos] = ch;
- pos++;
-
- // do not allow strings greater then 80 characters. This check prevents a crash for
- // users who do exceed the limit.
- if (pos > 79)
- break;
-
- // remove dedicated server garbage
- //putchar (ch);
- }
+void INI_Sentence(FILE* f, char result[80]) {
+ char ch;
+ int pos = 0;
+
+ // clear out entire string
+ for (int i = 0; i < 80; i++)
+ result[i] = '\0';
+
+ while (feof(f) == 0 && (ch = fgetc(f)) != '\n') {
+ result[pos] = ch;
+ pos++;
+
+ // do not allow strings greater then 80 characters. This check prevents a crash for
+ // users who do exceed the limit.
+ if (pos > 79)
+ break;
+
+ // remove dedicated server garbage
+ //putchar (ch);
+ }
}
// Reads out section[], does a string compare and returns type id
-int INI_SectionType(char section[30], int last) {
-
- if (strcmp(section, "BLOCK") == 0)
- return INI_BLOCK;
-
- if (strcmp(section, "DEATH") == 0)
- return INI_DEATHS;
-
- if (strcmp(section, "WELCOME") == 0)
- return INI_WELCOME;
-
- if (strcmp(section, "AREA") == 0)
- return INI_AREA;
-
- if (strcmp(section, "WEAPON") == 0)
- return INI_WEAPON;
-
- if (strcmp(section, "SKILL") == 0)
- return INI_SKILL;
-
- if (strcmp(section, "GAME") == 0)
- return INI_GAME;
-
- if (strcmp(section, "RADIO") == 0)
- return INI_RADIO;
-
- if (strcmp(section, "TEAM") == 0)
- return INI_TEAM;
-
- if (strcmp(section, "PERSON") == 0)
- return INI_PERSON;
-
- // When nothing found; we assume its just a new ID tag for some unit or structure
- // Therefor we return the last known SECTION ID so we can assign the proper WORD ID's
- return last;
+int INI_SectionType(char section[30], const int last) {
+ static const std::unordered_map sectionMap = {
+ {"BLOCK", INI_BLOCK},
+ {"DEATH", INI_DEATHS},
+ {"WELCOME", INI_WELCOME},
+ {"AREA", INI_AREA},
+ {"WEAPON", INI_WEAPON},
+ {"SKILL", INI_SKILL},
+ {"GAME", INI_GAME},
+ {"RADIO", INI_RADIO},
+ {"TEAM", INI_TEAM},
+ {"PERSON", INI_PERSON}
+ };
+
+ if (const std::unordered_map::const_iterator it = sectionMap.find(section); it != sectionMap.end()) {
+ return it->second;
+ }
+
+ // When nothing found; we assume its just a new ID tag for some unit or structure
+ // Therefor we return the last known SECTION ID so we can assign the proper WORD ID's
+ return last;
}
// Reads out section[], does a string compare and returns type id
// BUYTABLE.INI SPECIFIC!
-int INI_SectionType_BUYTABLE(char section[30], int last) {
-
- if (strcmp(section, "P228") == 0)
- return CS_WEAPON_P228;
- if (strcmp(section, "HEGRENADE") == 0)
- return CS_WEAPON_HEGRENADE;
- if (strcmp(section, "AK47") == 0)
- return CS_WEAPON_AK47;
- if (strcmp(section, "DEAGLE") == 0)
- return CS_WEAPON_DEAGLE;
- if (strcmp(section, "MAC10") == 0)
- return CS_WEAPON_MAC10;
- if (strcmp(section, "AUG") == 0)
- return CS_WEAPON_AUG;
- if (strcmp(section, "SG552") == 0)
- return CS_WEAPON_SG552;
- if (strcmp(section, "ELITE") == 0)
- return CS_WEAPON_ELITE;
- if (strcmp(section, "FIVESEVEN") == 0)
- return CS_WEAPON_FIVESEVEN;
- if (strcmp(section, "UMP45") == 0)
- return CS_WEAPON_UMP45;
- if (strcmp(section, "SG550") == 0)
- return CS_WEAPON_SG550;
- if (strcmp(section, "USP") == 0)
- return CS_WEAPON_USP;
- if (strcmp(section, "GLOCK18") == 0)
- return CS_WEAPON_GLOCK18;
- if (strcmp(section, "AWP") == 0)
- return CS_WEAPON_AWP;
- if (strcmp(section, "MP5") == 0)
- return CS_WEAPON_MP5NAVY;
- if (strcmp(section, "M249") == 0)
- return CS_WEAPON_M249;
- if (strcmp(section, "M3") == 0)
- return CS_WEAPON_M3;
- if (strcmp(section, "M4A1") == 0)
- return CS_WEAPON_M4A1;
- if (strcmp(section, "TMP") == 0)
- return CS_WEAPON_TMP;
- if (strcmp(section, "G3SG1") == 0)
- return CS_WEAPON_G3SG1;
- if (strcmp(section, "SCOUT") == 0)
- return CS_WEAPON_SCOUT;
- if (strcmp(section, "FLASHBANG") == 0)
- return CS_WEAPON_FLASHBANG;
- if (strcmp(section, "C4") == 0)
- return CS_WEAPON_C4;
- if (strcmp(section, "SMOKEGRENADE") == 0)
- return CS_WEAPON_SMOKEGRENADE;
- if (strcmp(section, "XM1014") == 0)
- return CS_WEAPON_XM1014;
- if (strcmp(section, "KNIFE") == 0)
- return CS_WEAPON_KNIFE;
- if (strcmp(section, "P90") == 0)
- return CS_WEAPON_P90;
-
- // Counter-Strike 1.6
- if (strcmp(section, "FAMAS") == 0)
- return CS_WEAPON_FAMAS;
- if (strcmp(section, "GALIL") == 0)
- return CS_WEAPON_GALIL;
-
- // Unconfirmed
- if (strcmp(section, "SHIELD") == 0)
- return CS_WEAPON_SHIELD;
-
- // When nothing found; we assume its just a new ID tag for some unit or structure
- // Therefor we return the last known SECTION ID so we can assign the proper WORD ID's
- return last;
+int INI_SectionType_BUYTABLE(char section[30], const int last) {
+ if (std::strcmp(section, "P228") == 0)
+ return CS_WEAPON_P228;
+ if (std::strcmp(section, "HEGRENADE") == 0)
+ return CS_WEAPON_HEGRENADE;
+ if (std::strcmp(section, "AK47") == 0)
+ return CS_WEAPON_AK47;
+ if (std::strcmp(section, "DEAGLE") == 0)
+ return CS_WEAPON_DEAGLE;
+ if (std::strcmp(section, "MAC10") == 0)
+ return CS_WEAPON_MAC10;
+ if (std::strcmp(section, "AUG") == 0)
+ return CS_WEAPON_AUG;
+ if (std::strcmp(section, "SG552") == 0)
+ return CS_WEAPON_SG552;
+ if (std::strcmp(section, "ELITE") == 0)
+ return CS_WEAPON_ELITE;
+ if (std::strcmp(section, "FIVESEVEN") == 0)
+ return CS_WEAPON_FIVESEVEN;
+ if (std::strcmp(section, "UMP45") == 0)
+ return CS_WEAPON_UMP45;
+ if (std::strcmp(section, "SG550") == 0)
+ return CS_WEAPON_SG550;
+ if (std::strcmp(section, "USP") == 0)
+ return CS_WEAPON_USP;
+ if (std::strcmp(section, "GLOCK18") == 0)
+ return CS_WEAPON_GLOCK18;
+ if (std::strcmp(section, "AWP") == 0)
+ return CS_WEAPON_AWP;
+ if (std::strcmp(section, "MP5") == 0)
+ return CS_WEAPON_MP5NAVY;
+ if (std::strcmp(section, "M249") == 0)
+ return CS_WEAPON_M249;
+ if (std::strcmp(section, "M3") == 0)
+ return CS_WEAPON_M3;
+ if (std::strcmp(section, "M4A1") == 0)
+ return CS_WEAPON_M4A1;
+ if (std::strcmp(section, "TMP") == 0)
+ return CS_WEAPON_TMP;
+ if (std::strcmp(section, "G3SG1") == 0)
+ return CS_WEAPON_G3SG1;
+ if (std::strcmp(section, "SCOUT") == 0)
+ return CS_WEAPON_SCOUT;
+ if (std::strcmp(section, "FLASHBANG") == 0)
+ return CS_WEAPON_FLASHBANG;
+ if (std::strcmp(section, "C4") == 0)
+ return CS_WEAPON_C4;
+ if (std::strcmp(section, "SMOKEGRENADE") == 0)
+ return CS_WEAPON_SMOKEGRENADE;
+ if (std::strcmp(section, "XM1014") == 0)
+ return CS_WEAPON_XM1014;
+ if (std::strcmp(section, "KNIFE") == 0)
+ return CS_WEAPON_KNIFE;
+ if (std::strcmp(section, "P90") == 0)
+ return CS_WEAPON_P90;
+
+ // Counter-Strike 1.6
+ if (std::strcmp(section, "FAMAS") == 0)
+ return CS_WEAPON_FAMAS;
+ if (std::strcmp(section, "GALIL") == 0)
+ return CS_WEAPON_GALIL;
+
+ if (std::strcmp(section, "SHIELD") == 0)
+ return CS_WEAPON_SHIELD;
+
+ // When nothing found; we assume its just a new ID tag for some unit or structure
+ // Therefor we return the last known SECTION ID so we can assign the proper WORD ID's
+ return last;
}
// Reads out 'result' and will return the value after the '='. Returns integer.
// For CHAR returns see "INI_WordValueCHAR(char result[80]);
int INI_WordValueINT(char result[80]) {
- int pos = 0;
- int is_pos = -1;
-
- while (pos < 79) {
- if (result[pos] == '=') {
- is_pos = pos;
- break;
- }
- pos++;
- }
-
- if (is_pos > -1) {
- // Whenever the IS (=) position is known, we make a number out of 'IS_POS' till the next empty
- // space.
- int end_pos = -1;
-
- while (pos < 79) {
- if (result[pos] == '\0') {
- end_pos = pos;
- break;
- }
- pos++;
- }
-
- // End position found!
- if (end_pos > -1) {
- // We know the END position. We will use that piece of string to read out a number.
- char number[10];
-
- // clear out entire string
- for (int i = 0; i < 10; i++)
- number[i] = '\0';
-
- // Copy the part to 'number', Make sure we won't get outside the array of the character.
- int cp = is_pos + 1;
- int c = 0;
- while (cp < end_pos) {
- number[c] = result[cp];
- c++;
- cp++;
- if (c > 9)
- break;
- }
-
- /*
- char aa[80];
- sprintf(aa, "Original %s, atoi %d\n", number, atoi(number));
- DebugOut(aa);
- */
-
- return atoi(number);
- }
- // nothing here, so we return NULL at the end
- }
-
- return 0; // No value, return 0 (was NULL)
+ int pos = 0;
+ int is_pos = -1;
+
+ while (pos < 79) {
+ if (result[pos] == '=') {
+ is_pos = pos;
+ break;
+ }
+ pos++;
+ }
+
+ if (is_pos > -1) {
+ // Whenever the IS (=) position is known, we make a number out of 'IS_POS' till the next empty
+ // space.
+ int end_pos = -1;
+
+ while (pos < 79) {
+ if (result[pos] == '\0') {
+ end_pos = pos;
+ break;
+ }
+ pos++;
+ }
+
+ // End position found!
+ if (end_pos > -1) {
+ // We know the END position. We will use that piece of string to read out a number.
+ char number[10];
+
+ // clear out entire string
+ for (char& i : number)
+ i = '\0';
+
+ // Copy the part to 'number', Make sure we won't get outside the array of the character.
+ int cp = is_pos + 1;
+ int c = 0;
+ while (cp < end_pos) {
+ number[c] = result[cp];
+ c++;
+ cp++;
+ if (c > 9)
+ break;
+ }
+
+ /*
+ char aa[80];
+ sprintf(aa, "Original %s, atoi %d\n", number, atoi(number));
+ DebugOut(aa);
+ */
+
+ return std::atoi(number);
+ }
+ // nothing here, so we return NULL at the end
+ }
+
+ return 0; // No value, return 0 (was NULL)
}
// Reads out 'result' and will return the value after the '='. Returns integer.
// For CHAR returns see "INI_WordValueCHAR(char result[80]);
float INI_WordValueFLOAT(char result[80]) {
- int pos = 0;
- int is_pos = -1;
-
- while (pos < 79) {
- if (result[pos] == '=') {
- is_pos = pos;
- break;
- }
- pos++;
- }
-
- if (is_pos > -1) {
- // Whenever the IS (=) position is known, we make a number out of 'IS_POS' till the next empty
- // space.
- int end_pos = -1;
-
- while (pos < 79) {
- if (result[pos] == '\0') {
- end_pos = pos;
- break;
- }
- pos++;
- }
-
- // End position found!
- if (end_pos > -1) {
- // We know the END position. We will use that piece of string to read out a number.
- char number[10];
-
- // clear out entire string
- for (int i = 0; i < 10; i++)
- number[i] = '\0';
-
- // Copy the part to 'number', Make sure we won't get outside the array of the character.
- int cp = is_pos + 1;
- int c = 0;
- while (cp < end_pos) {
- number[c] = result[cp];
- c++;
- cp++;
- if (c > 9)
- break;
- }
- return atof(number);
- }
- // nothing here, so we return NULL at the end
- }
-
- return 0.0; // No value, return 0.0 was NULL
+ int pos = 0;
+ int is_pos = -1;
+
+ while (pos < 79) {
+ if (result[pos] == '=') {
+ is_pos = pos;
+ break;
+ }
+ pos++;
+ }
+
+ if (is_pos > -1) {
+ // Whenever the IS (=) position is known, we make a number out of 'IS_POS' till the next empty
+ // space.
+ int end_pos = -1;
+
+ while (pos < 79) {
+ if (result[pos] == '\0') {
+ end_pos = pos;
+ break;
+ }
+ pos++;
+ }
+
+ // End position found!
+ if (end_pos > -1) {
+ // We know the END position. We will use that piece of string to read out a number.
+ char number[10];
+
+ // clear out entire string
+ for (char& i : number)
+ i = '\0';
+
+ // Copy the part to 'number', Make sure we won't get outside the array of the character.
+ int cp = is_pos + 1;
+ int c = 0;
+ while (cp < end_pos) {
+ number[c] = result[cp];
+ c++;
+ cp++;
+ if (c > 9)
+ break;
+ }
+ return static_cast(std::atof(number));
+ }
+ // nothing here, so we return NULL at the end
+ }
+
+ return 0.0; // No value, return 0.0 was NULL
}
// Reads out 'result' and will return the value after the '='. Returns nothing but will put
// the result in 'value[25]'. Max argument may be 25 characters!
void INI_WordValueCHAR(char result[80], char value[80]) {
- int pos = 0;
- int is_pos = -1;
-
- // clear out entire string
- for (int i = 0; i < 25; i++)
- value[i] = '\0';
-
- while (pos < 79) {
- if (result[pos] == '=') {
- is_pos = pos;
- break;
- }
- pos++;
- }
-
- if (is_pos > -1) {
- // Whenever the IS (=) position is known, we make a number out of 'IS_POS' till the next empty
- // space.
- int end_pos = -1;
-
- while (pos < 79) {
- if (result[pos] == '\0') {
- end_pos = pos;
- break;
- }
- pos++;
- }
-
- // End position found!
- if (end_pos > -1) {
- // We know the END position. We will use that piece of string to read out a number.
-
- // Copy the part to 'value', Make sure we won't get outside the array of the character.
- int cp = is_pos + 1;
- int c = 0;
- while (cp < end_pos) {
- value[c] = result[cp];
- c++;
- cp++;
- if (c > 79)
- break;
- }
- }
- }
+ int pos = 0;
+ int is_pos = -1;
+
+ // clear out entire string
+ for (int i = 0; i < 25; i++)
+ value[i] = '\0';
+
+ while (pos < 79) {
+ if (result[pos] == '=') {
+ is_pos = pos;
+ break;
+ }
+ pos++;
+ }
+
+ if (is_pos > -1) {
+ // Whenever the IS (=) position is known, we make a number out of 'IS_POS' till the next empty
+ // space.
+ int end_pos = -1;
+
+ while (pos < 79) {
+ if (result[pos] == '\0') {
+ end_pos = pos;
+ break;
+ }
+ pos++;
+ }
+
+ // End position found!
+ if (end_pos > -1) {
+ // We know the END position. We will use that piece of string to read out a number.
+
+ // Copy the part to 'value', Make sure we won't get outside the array of the character.
+ int cp = is_pos + 1;
+ int c = 0;
+ while (cp < end_pos) {
+ value[c] = result[cp];
+ c++;
+ cp++;
+ if (c > 79)
+ break;
+ }
+ }
+ }
}
// parses the chat file (loads in blocks)
void INI_PARSE_CHATFILE() {
- char dirname[256];
- char filename[256];
-
- FILE *stream;
- int section = INI_NONE;
- int wordtype = WORD_NONE;
-
-
- // Set Directory name + file
- strcpy(dirname, "data/cstrike/chat.ini");
-
- // writes whole path into "filename", Linux compatible
- UTIL_BuildFileNameRB(dirname, filename);
-
- // make sure the engine knows...
- REALBOT_PRINT(NULL, "INI_PARSE_CHATFILE", "Loading CHAT.INI\n");
-
- int iBlockId = -1;
- int iBlockWord = -1;
- int iBlockSentence = -1;
-
- // load it
- if ((stream = fopen(filename, "r+t")) != NULL) {
- char linefeed[80];
- char lineword[25];
- char linesection[30];
-
- // infinite loop baby
- while (!feof(stream)) {
- INI_Sentence(stream, linefeed);
-
- // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
- // character (which is "//", ";" or "#"), or an empty line, then skip it
- if (linefeed[0] == ';' ||
- linefeed[0] == '#' ||
- (linefeed[0] == '/' && linefeed[1] == '/') ||
- linefeed[0] == '\n' || linefeed[0] == '\0')
- continue; // Skip
-
- wordtype = WORD_NONE;
-
- // Every line is checked for a new section.
- INI_Section(linefeed, linesection);
-
- if (linesection[0] != '\0' && strlen(linesection) > 1) {
- section = INI_SectionType(linesection, section);
-
- if (section == INI_BLOCK) {
- iBlockId++;
- if (iBlockId > 97)
- iBlockId = 97;
- section = INI_NONE;
- iBlockWord = -1;
- iBlockSentence = -1;
- }
-
- if (section == INI_DEATHS) {
- iBlockId = 99; // 99 = death
- iBlockWord = -1;
- iBlockSentence = -1;
- section = INI_NONE;
- }
-
- if (section == INI_WELCOME) {
- iBlockId = 98; // 98 = welcome
- iBlockWord = -1;
- iBlockSentence = -1;
- section = INI_NONE;
- }
-
- continue; // next line
- }
-
- if (iBlockId > -1) {
- INI_Word(linefeed, lineword);
- wordtype = INI_WordType(lineword, section);
-
- // We load in words
- if (wordtype == WORD_WORD) {
- iBlockWord++;
- if (iBlockWord > 9)
- iBlockWord = 9;
-
- // write the word in the block
- char chWord[25];
- memset(chWord, 0, sizeof(chWord));
- INI_WordValueCHAR(linefeed, chWord);
- // lower case
- //chWord = _strlwr( _strdup( chWord ) );
+ char dirname[256];
+ char filename[256];
+
+ int section = INI_NONE;
+
+ // Set Directory name + file
+ std::strcpy(dirname, "data/cstrike/chat.ini");
+
+ // writes whole path into "filename", Linux compatible
+ UTIL_BuildFileNameRB(dirname, filename);
+
+ // make sure the engine knows...
+ REALBOT_PRINT(nullptr, "INI_PARSE_CHATFILE", "Loading CHAT.INI\n");
+
+ // load it
+ if (FILE* stream; (stream = std::fopen(filename, "r+t")) != nullptr) {
+
+ int iBlockId = -1;
+ int iBlockWord = -1;
+ int iBlockSentence = -1;
+
+ // infinite loop baby
+ while (!feof(stream)) {
+ char linesection[30];
+ char linefeed[80];
+ INI_Sentence(stream, linefeed);
+
+ // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
+ // character (which is "//", ";" or "#"), or an empty line, then skip it
+ if (linefeed[0] == ';' ||
+ linefeed[0] == '#' ||
+ (linefeed[0] == '/' && linefeed[1] == '/') ||
+ linefeed[0] == '\n' || linefeed[0] == '\0')
+ continue; // Skip
+
+ // Every line is checked for a new section.
+ INI_Section(linefeed, linesection);
+
+ if (linesection[0] != '\0' && std::strlen(linesection) > 1) {
+ section = INI_SectionType(linesection, section);
+
+ if (section == INI_BLOCK) {
+ iBlockId++;
+ iBlockId = std::min(iBlockId, 97);
+ section = INI_NONE;
+ iBlockWord = -1;
+ iBlockSentence = -1;
+ }
+
+ if (section == INI_DEATHS) {
+ iBlockId = 99; // 99 = death
+ iBlockWord = -1;
+ iBlockSentence = -1;
+ section = INI_NONE;
+ }
+
+ if (section == INI_WELCOME) {
+ iBlockId = 98; // 98 = welcome
+ iBlockWord = -1;
+ iBlockSentence = -1;
+ section = INI_NONE;
+ }
+
+ continue; // next line
+ }
+
+ if (iBlockId > -1) {
+ char lineword[25];
+ INI_Word(linefeed, lineword);
+ const int wordtype = INI_WordType(lineword, section);
+
+ // We load in words
+ if (wordtype == WORD_WORD) {
+ iBlockWord++;
+ iBlockWord = std::min(iBlockWord, 9);
+
+ // write the word in the block
+ char chWord[25] = {};
+ INI_WordValueCHAR(linefeed, chWord);
+ // lower case
+ //chWord = _strlwr( _strdup( chWord ) );
#ifdef _WIN32
- _strupr(chWord);
- // #elseif did not work for MSVC
+ _strupr(chWord);
+ // #elseif did not work for MSVC
#else
- //for linux by ok:
- // transform removed by evyncke since it works only on strings and not char array
- //further changed back by evyncke as these are normal string not CString
- //Hence, hardcoding the strupr inline...
- char *pString;
- pString = chWord;
- while (*pString) {
- *pString = toupper(*pString);
- pString++;
- }
+ //for linux by ok:
+ // transform removed by evyncke since it works only on strings and not char array
+ //further changed back by evyncke as these are normal string not CString
+ //Hence, hardcoding the strupr inline...
+ char* pString;
+ pString = chWord;
+ while (*pString) {
+ *pString = toupper(*pString);
+ pString++;
+ }
#endif
- strcpy(ChatEngine.ReplyBlock[iBlockId].word[iBlockWord],
- chWord);
- }
-
- if (wordtype == WORD_SENTENCE) {
- iBlockSentence++;
- if (iBlockSentence > 49)
- iBlockSentence = 49;
-
- // write the word in the block
- char chSentence[80];
- memset(chSentence, 0, sizeof(chSentence));
- INI_WordValueCHAR(linefeed, chSentence);
- strcpy(ChatEngine.ReplyBlock[iBlockId].
- sentence[iBlockSentence], chSentence);
-
- // here we say it is used
- ChatEngine.ReplyBlock[iBlockId].bUsed = true;
- }
- }
-
- } // while
-
- fclose(stream);
- }
+ std::strcpy(ChatEngine.ReplyBlock[iBlockId].word[iBlockWord],
+ chWord);
+ }
+
+ if (wordtype == WORD_SENTENCE) {
+ iBlockSentence++;
+ iBlockSentence = std::min(iBlockSentence, 49);
+
+ // write the word in the block
+ char chSentence[80] = {};
+ INI_WordValueCHAR(linefeed, chSentence);
+ std::strcpy(ChatEngine.ReplyBlock[iBlockId].
+ sentence[iBlockSentence], chSentence);
+
+ // here we say it is used
+ ChatEngine.ReplyBlock[iBlockId].bUsed = true;
+ }
+ }
+ } // while
+
+ std::fclose(stream);
+ }
}
// Parse IAD file:
// Important Area Definition file
void INI_PARSE_IAD() {
- char dirname[256];
- char filename[256];
-
- FILE *stream;
- int section = INI_NONE;
- int wordtype = WORD_NONE;
-
- // Set Directory name
- strcpy(dirname, "data/cstrike/ini/");
-
- strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, ".ini"); // nodes file
-
- // writes whole path into "filename", Linux compatible
- UTIL_BuildFileNameRB(dirname, filename);
-
- SERVER_PRINT(filename);
- SERVER_PRINT("\n");
-
- float AreaX, AreaY, AreaZ;
- AreaX = AreaY = AreaZ = 9999;
-
- if ((stream = fopen(filename, "r+t")) != NULL) {
- char linefeed[80];
- char lineword[25];
- char linesection[30];
-
- while (!feof(stream)) {
- INI_Sentence(stream, linefeed);
-
- // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
- // character (which is "//", ";" or "#"), or an empty line, then skip it
- if (linefeed[0] == ';' ||
- linefeed[0] == '#' ||
- (linefeed[0] == '/' && linefeed[1] == '/') ||
- linefeed[0] == '\n' || linefeed[0] == '\0')
- continue; // Skip
-
- wordtype = WORD_NONE;
-
- // Every line is checked for a new section.
- INI_Section(linefeed, linesection);
-
- if (linesection[0] != '\0' && strlen(linesection) > 1) {
- section = INI_SectionType(linesection, section);
- continue; // next line
- }
-
- // Check word only when in a section
- if (section != INI_NONE) {
- INI_Word(linefeed, lineword);
- wordtype = INI_WordType(lineword, section);
-
- if (section == INI_AREA) {
- if (wordtype == WORD_AREAX)
- AreaX = INI_WordValueINT(linefeed);
- if (wordtype == WORD_AREAY)
- AreaY = INI_WordValueINT(linefeed);
- if (wordtype == WORD_AREAZ)
- AreaZ = INI_WordValueINT(linefeed);
-
-
- if (AreaX != 9999 && AreaY != 9999 && AreaZ != 9999) {
- // add this to goal
- rblog("IAD: Adding an important area/goal\n");
- NodeMachine.addGoal(NULL, GOAL_IMPORTANT, Vector(AreaX, AreaY, AreaZ));
-
- AreaX = AreaY = AreaZ = 9999;
- }
- }
- }
-
- } // while
-
- fclose(stream);
- }
+ char dirname[256];
+ char filename[256];
+
+ FILE* stream;
+ int section = INI_NONE;
+
+ // Set Directory name
+ std::strcpy(dirname, "data/cstrike/ini/");
+
+ std::strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, ".ini"); // nodes file
+
+ // writes whole path into "filename", Linux compatible
+ UTIL_BuildFileNameRB(dirname, filename);
+
+ SERVER_PRINT(filename);
+ SERVER_PRINT("\n");
+
+ float AreaY, AreaZ;
+ float AreaX = AreaY = AreaZ = 9999;
+
+ if ((stream = std::fopen(filename, "r+t")) != nullptr) {
+ while (!feof(stream)) {
+ char linesection[30];
+ char linefeed[80];
+ INI_Sentence(stream, linefeed);
+
+ // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
+ // character (which is "//", ";" or "#"), or an empty line, then skip it
+ if (linefeed[0] == ';' ||
+ linefeed[0] == '#' ||
+ (linefeed[0] == '/' && linefeed[1] == '/') ||
+ linefeed[0] == '\n' || linefeed[0] == '\0')
+ continue; // Skip
+
+ // Every line is checked for a new section.
+ INI_Section(linefeed, linesection);
+
+ if (linesection[0] != '\0' && std::strlen(linesection) > 1) {
+ section = INI_SectionType(linesection, section);
+ continue; // next line
+ }
+
+ // Check word only when in a section
+ if (section != INI_NONE) {
+ char lineword[25];
+ INI_Word(linefeed, lineword);
+ const int wordtype = INI_WordType(lineword, section);
+
+ if (section == INI_AREA) {
+ if (wordtype == WORD_AREAX)
+ AreaX = static_cast(INI_WordValueINT(linefeed));
+ if (wordtype == WORD_AREAY)
+ AreaY = static_cast(INI_WordValueINT(linefeed));
+ if (wordtype == WORD_AREAZ)
+ AreaZ = static_cast(INI_WordValueINT(linefeed));
+
+ if (AreaX != 9999.0f && AreaY != 9999.0f && AreaZ != 9999.0f) {
+ // add this to goal
+ rblog("IAD: Adding an important area/goal\n");
+ NodeMachine.addGoal(nullptr, GOAL_IMPORTANT, Vector(AreaX, AreaY, AreaZ));
+
+ AreaX = AreaY = AreaZ = 9999;
+ }
+ }
+ }
+ } // while
+
+ std::fclose(stream);
+ }
}
// Parse personality file
-void INI_PARSE_BOTS(char cBotName[33], cBot * pBot) {
- /*
- Revisited: 02/07/05 - Stefan
- Last bug/issue report:
- - seems to overwrite personality file ? (loading does not work?)
- RESULT: There is no bug.
- - removed any messages sent by this function.
- */
-
- FILE *stream;
- int section = INI_NONE;
- int wordtype = WORD_NONE;
-
- char dirname[256];
- char filename[256];
-
- // Set Directory name
- if (mod_id == CSTRIKE_DLL)
- strcpy(dirname, "data/cstrike/bots/");
-
- //strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, cBotName);
- strcat(dirname, ".ini");
-
- // writes whole path into "filename", Linux compatible
- UTIL_BuildFileNameRB(dirname, filename);
-
- // we open the file here!
- if ((stream = fopen(filename, "r+t")) != NULL) {
- char linefeed[80];
- char lineword[25];
- char linesection[30];
-
- // infinite loop baby
- while (!feof(stream)) {
- INI_Sentence(stream, linefeed);
-
- // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
- // character (which is "//", ";" or "#"), or an empty line, then skip it
- if (linefeed[0] == ';' ||
- linefeed[0] == '#' ||
- (linefeed[0] == '/' && linefeed[1] == '/') ||
- linefeed[0] == '\n' || linefeed[0] == '\0')
- continue; // Skip
-
- wordtype = WORD_NONE;
-
- // Every line is checked for a new section.
- INI_Section(linefeed, linesection);
-
- if (linesection[0] != '\0' && strlen(linesection) > 1) {
- section = INI_SectionType(linesection, section);
- continue; // next line
- }
- // Check word only when in a section
- if (section != INI_NONE) {
- INI_Word(linefeed, lineword);
- wordtype = INI_WordType(lineword, section);
-
- // WEAPON
- if (section == INI_WEAPON) {
- // 30/07/04 Josh
- // Code optimization using a case instead of series of IF THEN
- switch (wordtype) {
-
- case WORD_PRIWEAPON:
- pBot->ipFavoPriWeapon = INI_WordValueINT(linefeed);
- break;
- case WORD_SECWEAPON:
- pBot->ipFavoSecWeapon = INI_WordValueINT(linefeed);
- break;
- case WORD_GRENADE:
- pBot->ipBuyGrenade = INI_WordValueINT(linefeed);
- break;
- case WORD_SAVEFORWEAP:
- pBot->ipSaveForWeapon = INI_WordValueINT(linefeed);
- break;
- case WORD_FLASHBANG:
- pBot->ipBuyFlashBang = INI_WordValueINT(linefeed);
- break;
- case WORD_SMOKEGREN:
- pBot->ipBuySmokeGren = INI_WordValueINT(linefeed);
- break;
- case WORD_DEFUSEKIT:
- pBot->ipBuyDefuseKit = INI_WordValueINT(linefeed);
- break;
- case WORD_ARMOUR:
- pBot->ipBuyArmour = INI_WordValueINT(linefeed);
- break;
- }
- }
- // SKILL
- if (section == INI_SKILL) {
- switch (wordtype) {
- case WORD_MINREACTTIME:
- pBot->fpMinReactTime = INI_WordValueFLOAT(linefeed);
- break;
- case WORD_MAXREACTTIME:
- pBot->fpMaxReactTime = INI_WordValueFLOAT(linefeed);
- break;
- case WORD_XOFFSET:
- pBot->fpXOffset = INI_WordValueFLOAT(linefeed);
- break;
- case WORD_YOFFSET:
- pBot->fpYOffset = INI_WordValueFLOAT(linefeed);
- break;
- case WORD_ZOFFSET:
- pBot->fpZOffset = INI_WordValueFLOAT(linefeed);
- break;
-
- }
- // default we override bot skill with personality skill
- if (Game.iOverrideBotSkill == GAME_YES)
- if (wordtype == WORD_BOTSKILL)
- pBot->bot_skill = INI_WordValueINT(linefeed);
- }
- // GAME
- if (section == INI_GAME) {
- if (wordtype == WORD_HOSTAGERATE)
- pBot->ipHostage = INI_WordValueINT(linefeed);
- if (wordtype == WORD_BOMBSPOTRATE)
- pBot->ipBombspot = INI_WordValueINT(linefeed);
- if (wordtype == WORD_RANDOMRATE)
- pBot->ipRandom = INI_WordValueINT(linefeed);
- if (wordtype == WORD_DROPPEDBOMB)
- pBot->ipDroppedBomb = INI_WordValueINT(linefeed);
- }
- // RADIO
- if (section == INI_RADIO) {
- if (wordtype == WORD_REPLYRADIO)
- pBot->ipReplyToRadio = INI_WordValueINT(linefeed);
- if (wordtype == WORD_CREATERADIO)
- pBot->ipCreateRadio = INI_WordValueINT(linefeed);
- }
- // TEAM
- if (section == INI_TEAM) {
- if (wordtype == WORD_HELPTEAM)
- pBot->ipHelpTeammate = INI_WordValueINT(linefeed);
- }
- // PERSON
- if (section == INI_PERSON) {
- if (wordtype == WORD_TURNSPEED)
- pBot->ipTurnSpeed = INI_WordValueINT(linefeed);
- if (wordtype == WORD_WALKKNIFE)
- pBot->ipWalkWithKnife = INI_WordValueINT(linefeed);
- if (wordtype == WORD_FEARRATE)
- pBot->ipFearRate = INI_WordValueINT(linefeed);
- if (wordtype == WORD_HEARRATE)
- pBot->ipHearRate = INI_WordValueINT(linefeed);
- if (wordtype == WORD_CHATRATE)
- pBot->ipChatRate = INI_WordValueINT(linefeed);
- if (wordtype == WORD_CAMPRATE)
- pBot->ipCampRate = INI_WordValueINT(linefeed);
- }
- }
- }
- fclose(stream);
- }
- // When we end up here, there is NO file?
- else {
- // Create new variables and save them into file.
-
- // Buy preferences
- pBot->ipFavoPriWeapon = -1;
- pBot->ipFavoSecWeapon = -1;
- pBot->ipBuyFlashBang = RANDOM_LONG(20, 80);
- pBot->ipBuyGrenade = RANDOM_LONG(20, 80);
- pBot->ipBuySmokeGren = RANDOM_LONG(20, 80);
- pBot->ipBuyDefuseKit = RANDOM_LONG(20, 80);
- pBot->ipDroppedBomb = RANDOM_LONG(20, 80);
- pBot->ipSaveForWeapon = RANDOM_LONG(0, 30);
- pBot->ipBuyArmour = RANDOM_LONG(30, 100);
- pBot->ipFearRate = RANDOM_LONG(20, 60);
-
-
- // Skill, everything but botskill can change.
-
- // Determine reaction time based upon botskill here
- float fMinReact = 0.0, fMaxReact;
- if (pBot->bot_skill == 0)
- fMinReact = 0.0;
- else
- //30.8.04 redefined by frashman
- // fMinReact = RANDOM_FLOAT (0.05, (pBot->bot_skill / 10));
- fMinReact =
- RANDOM_FLOAT((pBot->bot_skill / 20) + 0.05,
- (pBot->bot_skill / 5) + 0.05);
-
- fMaxReact = fMinReact + RANDOM_FLOAT(0.05, 0.2);
-
- // SET them
- pBot->fpMinReactTime = fMinReact;
- pBot->fpMaxReactTime = fMaxReact;
-
- // Set Offsets (note, they are extra upon current aiming code)
- // 30.8.04 redefined by frashman
- // float fOffset = RANDOM_FLOAT ((pBot->bot_skill / 5), (pBot->bot_skill / 2));
- float fOffset = RANDOM_FLOAT((pBot->bot_skill / 5) + 0.05,
- (pBot->bot_skill / 2) + 0.05);
-
- // SET
- pBot->fpXOffset = pBot->fpYOffset = pBot->fpZOffset = fOffset;
-
- // Team
- pBot->ipHelpTeammate = RANDOM_LONG(10, 70);
-
- // Game
- pBot->ipHostage = RANDOM_LONG(25, 70);
- pBot->ipBombspot = RANDOM_LONG(25, 70);
- pBot->ipRandom = RANDOM_LONG(25, 70);
-
- // Radio
- pBot->ipReplyToRadio = RANDOM_LONG(10, 60);
- pBot->ipCreateRadio = RANDOM_LONG(10, 60);
- pBot->ipHearRate = RANDOM_LONG(10, 60);
-
- // Person
- pBot->ipTurnSpeed = RANDOM_LONG(20, 40);
- pBot->ipCampRate = RANDOM_LONG(0, 60);
- pBot->ipChatRate = RANDOM_LONG(0, 30);
- pBot->ipWalkWithKnife = RANDOM_LONG(0, 60);
-
- // SAVE TO DISK:
- char dirname[256];
- char filename[256];
-
- // Set Directory name
- if (mod_id == CSTRIKE_DLL)
- strcpy(dirname, "data/cstrike/bots/");
-
- strcat(dirname, cBotName);
- strcat(dirname, ".ini");
-
- // writes whole path into "filename", Linux compatible
- UTIL_BuildFileNameRB(dirname, filename);
-
- FILE *rbl;
-
- // Only save if lock type is < 1
- rbl = fopen(filename, "w+t");
-
- // Created file
- if (rbl != NULL) {
- fprintf(rbl, "; RealBot\n");
- fprintf(rbl, "; \n");
- fprintf(rbl,
- "; This personality is created with random values. You may\n; change this file to create your own personality.\n\n");
-
- // WEAPON
- fprintf(rbl, "[WEAPON]\n");
- fprintf(rbl, "PrimaryWeapon=%d\n", pBot->ipFavoPriWeapon);
- fprintf(rbl, "SecondaryWeapon=%d\n", pBot->ipFavoSecWeapon);
- fprintf(rbl, "SaveForWeapon=%d\n", pBot->ipSaveForWeapon);
- fprintf(rbl, "Grenade=%d\n", pBot->ipBuyGrenade);
- fprintf(rbl, "Flashbang=%d\n", pBot->ipBuyFlashBang);
- fprintf(rbl, "SmokeGrenade=%d\n", pBot->ipBuySmokeGren);
- fprintf(rbl, "DefuseKit=%d\n", pBot->ipBuyDefuseKit);
- fprintf(rbl, "Armour=%d\n", pBot->ipBuyArmour);
- fprintf(rbl, "\n");
-
-
- // SKILL
- fprintf(rbl, "[SKILL]\n");
- fprintf(rbl, "XOffset=%f\n", pBot->fpXOffset);
- fprintf(rbl, "YOffset=%f\n", pBot->fpYOffset);
- fprintf(rbl, "ZOffset=%f\n", pBot->fpZOffset);
- fprintf(rbl, "BotSkill=%d\n", pBot->bot_skill);
- fprintf(rbl, "MaxReactionTime=%f\n", pBot->fpMaxReactTime);
- fprintf(rbl, "MinReactionTime=%f\n", pBot->fpMinReactTime);
- fprintf(rbl, "\n");
-
- // GAME
- fprintf(rbl, "[GAME]\n");
- fprintf(rbl, "Hostage=%d\n", pBot->ipHostage);
- fprintf(rbl, "BombSpot=%d\n", pBot->ipBombspot);
- fprintf(rbl, "DroppedBomb=%d\n", pBot->ipDroppedBomb);
- fprintf(rbl, "Random=%d\n", pBot->ipRandom);
- fprintf(rbl, "\n");
-
- // RADIO
- fprintf(rbl, "[RADIO]\n");
- fprintf(rbl, "Reply=%d\n", pBot->ipReplyToRadio);
- fprintf(rbl, "Create=%d\n", pBot->ipCreateRadio);
- fprintf(rbl, "\n");
-
- // TEAM
- fprintf(rbl, "[TEAM]\n");
- fprintf(rbl, "HelpTeammate=%d\n", pBot->ipHelpTeammate);
- fprintf(rbl, "\n");
-
- // PERSON
- fprintf(rbl, "[PERSON]\n");
- fprintf(rbl, "Turnspeed=%d\n", pBot->ipTurnSpeed);
- fprintf(rbl, "WalkWithKnife=%d\n", pBot->ipWalkWithKnife);
- fprintf(rbl, "HearRate=%d\n", pBot->ipHearRate);
- fprintf(rbl, "FearRate=%d\n", pBot->ipFearRate);
- fprintf(rbl, "ChatRate=%d\n", pBot->ipChatRate);
- fprintf(rbl, "CampRate=%d\n", pBot->ipCampRate);
- fprintf(rbl, "\n");
-
- // Close file
- fclose(rbl);
- }
- }
+void INI_PARSE_BOTS(char cBotName[33], cBot* pBot) {
+ /*
+ Revisited: 02/07/05 - Stefan
+ Last bug/issue report:
+ - seems to overwrite personality file ? (loading does not work?)
+ RESULT: There is no bug.
+ - removed any messages sent by this function.
+ */
+
+ FILE* stream;
+ int section = INI_NONE;
+
+ char dirname[256];
+ char filename[256];
+
+ // Set Directory name
+ if (mod_id == CSTRIKE_DLL)
+ std::strcpy(dirname, "data/cstrike/bots/");
+
+ //strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, cBotName);
+ std::strcat(dirname, ".ini");
+
+ // writes whole path into "filename", Linux compatible
+ UTIL_BuildFileNameRB(dirname, filename);
+
+ // we open the file here!
+ if ((stream = std::fopen(filename, "r+t")) != nullptr) {
+ // infinite loop baby
+ while (!feof(stream)) {
+ char linesection[30];
+ char linefeed[80];
+ INI_Sentence(stream, linefeed);
+
+ // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
+ // character (which is "//", ";" or "#"), or an empty line, then skip it
+ if (linefeed[0] == ';' ||
+ linefeed[0] == '#' ||
+ (linefeed[0] == '/' && linefeed[1] == '/') ||
+ linefeed[0] == '\n' || linefeed[0] == '\0')
+ continue; // Skip
+
+ // Every line is checked for a new section.
+ INI_Section(linefeed, linesection);
+
+ if (linesection[0] != '\0' && std::strlen(linesection) > 1) {
+ section = INI_SectionType(linesection, section);
+ continue; // next line
+ }
+ // Check word only when in a section
+ if (section != INI_NONE) {
+ char lineword[25];
+ INI_Word(linefeed, lineword);
+ const int wordtype = INI_WordType(lineword, section);
+
+ // WEAPON
+ if (section == INI_WEAPON) {
+ // 30/07/04 Josh
+ // Code optimization using a case instead of series of IF THEN
+ switch (wordtype) {
+ case WORD_PRIWEAPON:
+ pBot->ipFavoPriWeapon = INI_WordValueINT(linefeed);
+ break;
+ case WORD_SECWEAPON:
+ pBot->ipFavoSecWeapon = INI_WordValueINT(linefeed);
+ break;
+ case WORD_GRENADE:
+ pBot->ipBuyGrenade = INI_WordValueINT(linefeed);
+ break;
+ case WORD_SAVEFORWEAP:
+ pBot->ipSaveForWeapon = INI_WordValueINT(linefeed);
+ break;
+ case WORD_FLASHBANG:
+ pBot->ipBuyFlashBang = INI_WordValueINT(linefeed);
+ break;
+ case WORD_SMOKEGREN:
+ pBot->ipBuySmokeGren = INI_WordValueINT(linefeed);
+ break;
+ case WORD_DEFUSEKIT:
+ pBot->ipBuyDefuseKit = INI_WordValueINT(linefeed);
+ break;
+ case WORD_ARMOUR:
+ pBot->ipBuyArmour = INI_WordValueINT(linefeed);
+ break;
+ }
+ }
+ // SKILL
+ if (section == INI_SKILL) {
+ switch (wordtype) {
+ case WORD_MINREACTTIME:
+ pBot->fpMinReactTime = INI_WordValueFLOAT(linefeed);
+ break;
+ case WORD_MAXREACTTIME:
+ pBot->fpMaxReactTime = INI_WordValueFLOAT(linefeed);
+ break;
+ case WORD_XOFFSET:
+ pBot->fpXOffset = INI_WordValueFLOAT(linefeed);
+ break;
+ case WORD_YOFFSET:
+ pBot->fpYOffset = INI_WordValueFLOAT(linefeed);
+ break;
+ case WORD_ZOFFSET:
+ pBot->fpZOffset = INI_WordValueFLOAT(linefeed);
+ break;
+ }
+ // default we override bot skill with personality skill
+ if (Game.iOverrideBotSkill == GAME_YES)
+ if (wordtype == WORD_BOTSKILL)
+ pBot->bot_skill = INI_WordValueINT(linefeed);
+ }
+ // GAME
+ if (section == INI_GAME) {
+ if (wordtype == WORD_HOSTAGERATE)
+ pBot->ipHostage = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_BOMBSPOTRATE)
+ pBot->ipBombspot = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_RANDOMRATE)
+ pBot->ipRandom = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_DROPPEDBOMB)
+ pBot->ipDroppedBomb = INI_WordValueINT(linefeed);
+ }
+ // RADIO
+ if (section == INI_RADIO) {
+ if (wordtype == WORD_REPLYRADIO)
+ pBot->ipReplyToRadio = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_CREATERADIO)
+ pBot->ipCreateRadio = INI_WordValueINT(linefeed);
+ }
+ // TEAM
+ if (section == INI_TEAM) {
+ if (wordtype == WORD_HELPTEAM)
+ pBot->ipHelpTeammate = INI_WordValueINT(linefeed);
+ }
+ // PERSON
+ if (section == INI_PERSON) {
+ if (wordtype == WORD_TURNSPEED)
+ pBot->ipTurnSpeed = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_WALKKNIFE)
+ pBot->ipWalkWithKnife = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_FEARRATE)
+ pBot->ipFearRate = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_HEARRATE)
+ pBot->ipHearRate = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_CHATRATE)
+ pBot->ipChatRate = INI_WordValueINT(linefeed);
+ if (wordtype == WORD_CAMPRATE)
+ pBot->ipCampRate = INI_WordValueINT(linefeed);
+ }
+ }
+ }
+ std::fclose(stream);
+ }
+ // When we end up here, there is NO file?
+ else {
+ // Create new variables and save them into file.
+
+ // Buy preferences
+ pBot->ipFavoPriWeapon = -1;
+ pBot->ipFavoSecWeapon = -1;
+ pBot->ipBuyFlashBang = RANDOM_LONG(20, 80);
+ pBot->ipBuyGrenade = RANDOM_LONG(20, 80);
+ pBot->ipBuySmokeGren = RANDOM_LONG(20, 80);
+ pBot->ipBuyDefuseKit = RANDOM_LONG(20, 80);
+ pBot->ipDroppedBomb = RANDOM_LONG(20, 80);
+ pBot->ipSaveForWeapon = RANDOM_LONG(0, 20);
+ pBot->ipBuyArmour = RANDOM_LONG(30, 100);
+ pBot->ipFearRate = RANDOM_LONG(20, 60);
+
+ // Skill, everything but botskill can change.
+
+ // Determine reaction time based upon botskill here
+ float fMinReact;
+ if (pBot->bot_skill == 0)
+ fMinReact = 0.0f;
+ else
+ //30.8.04 redefined by frashman
+ // fMinReact = RANDOM_FLOAT (0.05, (pBot->bot_skill / 10));
+ // Reaction Time delay added for realistic gameplay [APG]RoboCop[CL]
+ fMinReact =
+ RANDOM_FLOAT(pBot->bot_skill / 20.0f + 0.3f,
+ pBot->bot_skill / 5.0f + 0.3f);
+
+ const float fMaxReact = fMinReact + RANDOM_FLOAT(0.2f, 0.4f);
+
+ // SET them
+ pBot->fpMinReactTime = fMinReact;
+ pBot->fpMaxReactTime = fMaxReact;
+
+ // Set Offsets (note, they are extra upon current aiming code)
+ // 30.8.04 redefined by frashman
+ // float fOffset = RANDOM_FLOAT ((pBot->bot_skill / 5), (pBot->bot_skill / 2));
+ const float fOffset = RANDOM_FLOAT(pBot->bot_skill / 5.0f + 0.05f,
+ pBot->bot_skill / 2.0f + 0.05f);
+
+ // SET
+ pBot->fpXOffset = pBot->fpYOffset = pBot->fpZOffset = fOffset;
+
+ // Team
+ pBot->ipHelpTeammate = RANDOM_LONG(40, 80);
+
+ // Game
+ pBot->ipHostage = RANDOM_LONG(25, 70);
+ pBot->ipBombspot = RANDOM_LONG(25, 70);
+ pBot->ipRandom = RANDOM_LONG(40, 80);
+
+ // Radio
+ pBot->ipReplyToRadio = RANDOM_LONG(10, 20);
+ pBot->ipCreateRadio = RANDOM_LONG(10, 20);
+ pBot->ipHearRate = RANDOM_LONG(20, 60);
+
+ // Person
+ pBot->ipTurnSpeed = RANDOM_LONG(20, 40);
+ pBot->ipCampRate = RANDOM_LONG(0, 40);
+ pBot->ipChatRate = RANDOM_LONG(10, 20);
+ pBot->ipWalkWithKnife = RANDOM_LONG(0, 30);
+
+ // SAVE TO DISK:
+ //char dirname[256];
+ //char filename[256];
+
+ // Set Directory name
+ if (mod_id == CSTRIKE_DLL)
+ std::strcpy(dirname, "data/cstrike/bots/");
+
+ std::strcat(dirname, cBotName);
+ std::strcat(dirname, ".ini");
+
+ // writes whole path into "filename", Linux compatible
+ UTIL_BuildFileNameRB(dirname, filename);
+
+ // Only save if lock type is < 1
+ FILE* rbl = std::fopen(filename, "w+t");
+
+ // Created file
+ if (rbl != nullptr) {
+ std::fprintf(rbl, "; RealBot\n");
+ std::fprintf(rbl, "; \n");
+ std::fprintf(rbl,
+ "; This personality is created with random values. You may\n; change this file to create your own personality.\n\n");
+
+ // WEAPON
+ std::fprintf(rbl, "[WEAPON]\n");
+ std::fprintf(rbl, "PrimaryWeapon=%d\n", pBot->ipFavoPriWeapon);
+ std::fprintf(rbl, "SecondaryWeapon=%d\n", pBot->ipFavoSecWeapon);
+ std::fprintf(rbl, "SaveForWeapon=%d\n", pBot->ipSaveForWeapon);
+ std::fprintf(rbl, "Grenade=%d\n", pBot->ipBuyGrenade);
+ std::fprintf(rbl, "Flashbang=%d\n", pBot->ipBuyFlashBang);
+ std::fprintf(rbl, "SmokeGrenade=%d\n", pBot->ipBuySmokeGren);
+ std::fprintf(rbl, "DefuseKit=%d\n", pBot->ipBuyDefuseKit);
+ std::fprintf(rbl, "Armour=%d\n", pBot->ipBuyArmour);
+ std::fprintf(rbl, "\n");
+
+ // SKILL
+ std::fprintf(rbl, "[SKILL]\n");
+ std::fprintf(rbl, "XOffset=%f\n", pBot->fpXOffset);
+ std::fprintf(rbl, "YOffset=%f\n", pBot->fpYOffset);
+ std::fprintf(rbl, "ZOffset=%f\n", pBot->fpZOffset);
+ std::fprintf(rbl, "BotSkill=%d\n", pBot->bot_skill);
+ std::fprintf(rbl, "MaxReactionTime=%f\n", pBot->fpMaxReactTime);
+ std::fprintf(rbl, "MinReactionTime=%f\n", pBot->fpMinReactTime);
+ std::fprintf(rbl, "\n");
+
+ // GAME
+ std::fprintf(rbl, "[GAME]\n");
+ std::fprintf(rbl, "Hostage=%d\n", pBot->ipHostage);
+ std::fprintf(rbl, "BombSpot=%d\n", pBot->ipBombspot);
+ std::fprintf(rbl, "DroppedBomb=%d\n", pBot->ipDroppedBomb);
+ std::fprintf(rbl, "Random=%d\n", pBot->ipRandom);
+ std::fprintf(rbl, "\n");
+
+ // RADIO
+ std::fprintf(rbl, "[RADIO]\n");
+ std::fprintf(rbl, "Reply=%d\n", pBot->ipReplyToRadio);
+ std::fprintf(rbl, "Create=%d\n", pBot->ipCreateRadio);
+ std::fprintf(rbl, "\n");
+
+ // TEAM
+ std::fprintf(rbl, "[TEAM]\n");
+ std::fprintf(rbl, "HelpTeammate=%d\n", pBot->ipHelpTeammate);
+ std::fprintf(rbl, "\n");
+
+ // PERSON
+ std::fprintf(rbl, "[PERSON]\n");
+ std::fprintf(rbl, "Turnspeed=%d\n", pBot->ipTurnSpeed);
+ std::fprintf(rbl, "WalkWithKnife=%d\n", pBot->ipWalkWithKnife);
+ std::fprintf(rbl, "HearRate=%d\n", pBot->ipHearRate);
+ std::fprintf(rbl, "FearRate=%d\n", pBot->ipFearRate);
+ std::fprintf(rbl, "ChatRate=%d\n", pBot->ipChatRate);
+ std::fprintf(rbl, "CampRate=%d\n", pBot->ipCampRate);
+ std::fprintf(rbl, "\n");
+
+ // Close file
+ std::fclose(rbl);
+ }
+ }
} // INI parsing
/**
@@ -1074,93 +961,90 @@ void INI_PARSE_BOTS(char cBotName[33], cBot * pBot) {
* The buytable.ini is not in the source file, but in the binary downloads of REALBOT.
*/
void INI_PARSE_BUYTABLE() {
- FILE *stream;
- int section = INI_NONE;
- int wordtype = WORD_NONE;
- int prev_section = section;
- int weapon_id = -1;
-
- char dirname[256];
- char filename[256];
-
- // Set Directory name
- if (mod_id == CSTRIKE_DLL)
- strcpy(dirname, "data/cstrike/");
-
- //strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, "buytable.ini");
-
- // writes whole path into "filename", Linux compatible
- UTIL_BuildFileNameRB(dirname, filename);
-
- // clear out weapon table completely
- for (int cl = 0; cl < 32; cl++) {
- weapons_table[cl].iId = -1;
- weapons_table[cl].price = -1;
- weapons_table[cl].priority = -1;
- weapons_table[cl].iIdIndex = -1;
- }
-
- if ((stream = fopen(filename, "r+t")) != NULL) {
- char linefeed[80];
- char lineword[25];
- char linesection[30];
-
- while (!feof(stream)) {
- INI_Sentence(stream, linefeed);
-
- // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
- // character (which is "//", ";" or "#"), or an empty line, then skip it
- if (linefeed[0] == ';' ||
- linefeed[0] == '#' ||
- (linefeed[0] == '/' && linefeed[1] == '/') ||
- linefeed[0] == '\n' || linefeed[0] == '\0')
- continue; // Skip
-
- wordtype = WORD_NONE;
-
- // Every line is checked for a new section.
- INI_Section(linefeed, linesection);
-
- // Found a new section
- if (linesection[0] != '\0' && strlen(linesection) > 1) {
- section = INI_SectionType_BUYTABLE(linesection, section);
- // Check if its the same as the previous section
- if (section != prev_section) {
- weapon_id++; // new weapon
- if (weapon_id > MAX_WEAPONS - 1) {
- // done
- fclose(stream);
- break; // out of the loop
- }
-
- weapons_table[weapon_id].iId = section;
- weapons_table[section].iIdIndex = weapon_id;
- }
-
- prev_section = section; // Equal the sections now
- continue; // next line
- }
-
- // Check word only when in a section
- if (section != INI_NONE) {
- INI_Word(linefeed, lineword);
- wordtype = INI_WordType(lineword, section);
- if (wordtype != WORD_NONE) {
- if (wordtype == WORD_PRICE) {
- //BotDebug("Loading price\n");
- weapons_table[weapon_id].price =
- INI_WordValueINT(linefeed);
- } else if (wordtype == WORD_PRIORITY) {
- //BotDebug("Loading priority\n");
- weapons_table[weapons_table[weapon_id].iId].priority =
- INI_WordValueINT(linefeed);
- }
- }
- }
- }
- fclose(stream);
- }
+ FILE* stream;
+ int section = INI_NONE;
+ int prev_section = section;
+ int weapon_id = -1;
+
+ char dirname[256];
+ char filename[256];
+
+ // Set Directory name
+ if (mod_id == CSTRIKE_DLL)
+ std::strcpy(dirname, "data/cstrike/");
+
+ //strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, "buytable.ini");
+
+ // writes whole path into "filename", Linux compatible
+ UTIL_BuildFileNameRB(dirname, filename);
+
+ // clear out weapon table completely
+ for (weapon_price_table& cl : weapons_table)
+ {
+ cl.iId = -1;
+ cl.price = -1;
+ cl.priority = -1;
+ cl.iIdIndex = -1;
+ }
+
+ if ((stream = std::fopen(filename, "r+t")) != nullptr) {
+ while (!feof(stream)) {
+ char linesection[30];
+ char linefeed[80];
+ INI_Sentence(stream, linefeed);
+
+ // Linefeed contains a string of 1 sentence. Whenever the first character is a commentary
+ // character (which is "//", ";" or "#"), or an empty line, then skip it
+ if (linefeed[0] == ';' ||
+ linefeed[0] == '#' ||
+ (linefeed[0] == '/' && linefeed[1] == '/') ||
+ linefeed[0] == '\n' || linefeed[0] == '\0')
+ continue; // Skip
+
+ // Every line is checked for a new section.
+ INI_Section(linefeed, linesection);
+
+ // Found a new section
+ if (linesection[0] != '\0' && std::strlen(linesection) > 1) {
+ section = INI_SectionType_BUYTABLE(linesection, section);
+ // Check if its the same as the previous section
+ if (section != prev_section) {
+ weapon_id++; // new weapon
+ if (weapon_id > MAX_WEAPONS - 1) {
+ // done
+ //std::fclose(stream);
+ break; // out of the loop
+ }
+
+ weapons_table[weapon_id].iId = section;
+ weapons_table[section].iIdIndex = weapon_id;
+ }
+
+ prev_section = section; // Equal the sections now
+ continue; // next line
+ }
+
+ // Check word only when in a section
+ if (section != INI_NONE) {
+ char lineword[25];
+ INI_Word(linefeed, lineword);
+ const int wordtype = INI_WordType(lineword, section);
+ if (wordtype != WORD_NONE) {
+ if (wordtype == WORD_PRICE) {
+ //BotDebug("Loading price\n");
+ weapons_table[weapon_id].price =
+ INI_WordValueINT(linefeed);
+ } else if (wordtype == WORD_PRIORITY) {
+ //BotDebug("Loading priority\n");
+ weapons_table[weapons_table[weapon_id].iId].priority =
+ INI_WordValueINT(linefeed);
+ }
+ }
+ }
+ }
+ std::fclose(stream);
+ }
} // INI parsing
// $Log: IniParser.cpp,v $
@@ -1235,4 +1119,4 @@ void INI_PARSE_BUYTABLE() {
// - Log() works properly now
// - Clearing in dll.cpp of reallog.txt at dll init
// - Logging works now, add REALBOT_PRINT() at every point you want to log something.
-//
+//
\ No newline at end of file
diff --git a/IniParser.h b/IniParser.h
index 3e0284f..4a661ee 100644
--- a/IniParser.h
+++ b/IniParser.h
@@ -33,88 +33,104 @@
**/
// Sections
-#define INI_NONE -1
-#define INI_SKILL 0 // Bot skill
-#define INI_WEAPON 1 // Bot weapon preference
-#define INI_GAME 2 // Bot general game behaviour
-#define INI_RADIO 3 // Bot radio behaviour
-#define INI_TEAM 4 // Bot team behaviour
-#define INI_PERSON 5 // Bot person itself
-
-#define INI_AREA 10
-#define INI_BLOCK 11
-#define INI_DEATHS 12
-#define INI_WELCOME 13
+#ifndef INIPARSER_H
+#define INIPARSER_H
+
+enum : std::int8_t
+{
+ INI_NONE = (-1),
+ INI_SKILL = 0, // Bot skill
+ INI_WEAPON = 1, // Bot weapon preference
+ INI_GAME = 2, // Bot general game behaviour
+ INI_RADIO = 3, // Bot radio behaviour
+ INI_TEAM = 4, // Bot team behaviour
+ INI_PERSON = 5 // Bot person itself
+};
+
+enum : std::uint8_t
+{
+ INI_AREA = 10,
+ INI_BLOCK = 11,
+ INI_DEATHS = 12,
+ INI_WELCOME = 13
+};
// 'Weapon Sections' are the same as WEAPON ID in Counter-Strike.
// NOTE: For weapon_buy_table.iId!
// 'Words'
-#define WORD_NONE -1
-#define WORD_WALK 0
-#define WORD_RUN 1
-#define WORD_SHOOT 2
-#define WORD_WAIT 3
-#define WORD_RADIO 4
+enum : std::int8_t
+{
+ WORD_NONE = (-1),
+ WORD_WALK = 0,
+ WORD_RUN = 1,
+ WORD_SHOOT = 2,
+ WORD_WAIT = 3,
+ WORD_RADIO = 4
+};
// BOTPERSONALITY.INI words
-#define WORD_PRIWEAPON 31
-#define WORD_SECWEAPON 32
-#define WORD_SAVEFORWEAP 33
-#define WORD_GRENADE 34
-#define WORD_FLASHBANG 35
-#define WORD_SMOKEGREN 36
-#define WORD_DEFUSEKIT 37
-#define WORD_ARMOUR 54
-
-#define WORD_XOFFSET 38
-#define WORD_YOFFSET 39
-#define WORD_ZOFFSET 40
-#define WORD_BOTSKILL 41
-#define WORD_MAXREACTTIME 42
-#define WORD_MINREACTTIME 43
-#define WORD_TURNSPEED 44
-
-#define WORD_HOSTAGERATE 45
-#define WORD_BOMBSPOTRATE 46
-#define WORD_RANDOMRATE 47
-
-#define WORD_REPLYRADIO 48
-#define WORD_CREATERADIO 49
-
-#define WORD_HELPTEAM 50
-
-#define WORD_CAMPRATE 51
-#define WORD_CHATRATE 52
-#define WORD_WALKKNIFE 53
-
-#define WORD_FEARRATE 55
-#define WORD_HEARRATE 56
-
-#define WORD_DROPPEDBOMB 57
+enum : std::uint8_t
+{
+ WORD_PRIWEAPON = 31,
+ WORD_SECWEAPON = 32,
+ WORD_SAVEFORWEAP = 33,
+ WORD_GRENADE = 34,
+ WORD_FLASHBANG = 35,
+ WORD_SMOKEGREN = 36,
+ WORD_DEFUSEKIT = 37,
+ WORD_ARMOUR = 54,
+ WORD_XOFFSET = 38,
+ WORD_YOFFSET = 39,
+ WORD_ZOFFSET = 40,
+ WORD_BOTSKILL = 41,
+ WORD_MAXREACTTIME = 42,
+ WORD_MINREACTTIME = 43,
+ WORD_TURNSPEED = 44,
+
+ WORD_HOSTAGERATE = 45,
+ WORD_BOMBSPOTRATE = 46,
+ WORD_RANDOMRATE = 47,
+
+ WORD_REPLYRADIO = 48,
+ WORD_CREATERADIO = 49,
+
+ WORD_HELPTEAM = 50,
+
+ WORD_CAMPRATE = 51,
+ WORD_CHATRATE = 52,
+ WORD_WALKKNIFE = 53,
+
+ WORD_FEARRATE = 55,
+ WORD_HEARRATE = 56,
+
+ WORD_DROPPEDBOMB = 57,
// AREA SHIT
-#define WORD_AREAX 60
-#define WORD_AREAY 61
-#define WORD_AREAZ 62
+ WORD_AREAX = 60,
+ WORD_AREAY = 61,
+ WORD_AREAZ = 62,
// CHAT
-#define WORD_SENTENCE 67
-#define WORD_WORD 68
+ WORD_SENTENCE = 67,
+ WORD_WORD = 68,
// BUYTABLE.INI Words (arguments per weapon)
-#define WORD_PRIORITY 5
-#define WORD_PRICE 6
-#define WORD_MAXAMMO1 88
-#define WORD_MAXAMMO2 89
-#define WORD_ISLOT 90
-#define WORD_IPOSITION 91
-#define WORD_IFLAGS 92
-#define WORD_INDEX1 93
-#define WORD_INDEX2 94
+ WORD_PRIORITY = 5,
+ WORD_PRICE = 6,
+ WORD_MAXAMMO1 = 88,
+ WORD_MAXAMMO2 = 89,
+ WORD_ISLOT = 90,
+ WORD_IPOSITION = 91,
+ WORD_IFLAGS = 92,
+ WORD_INDEX1 = 93,
+ WORD_INDEX2 = 94
+};
void INI_PARSE_BOTS(char cBotName[33], cBot * pBot);
void INI_PARSE_BUYTABLE();
void INI_PARSE_IAD();
void INI_PARSE_CHATFILE();
+
+#endif // INIPARSER_H
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 8f63e21..1431dc9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,14 @@
CPP = g++
-
ARCHFLAG = -m32
-METAMOD_SRCDIR = ./dependencies/metamod-hl1/metamod
-HLSDK_BASEDIR = ./dependencies/hlsdk
+META_DIR = ./dependencies/metamod-hl1/metamod
+HLSDK_DIR = ./dependencies/hlsdk
BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -Dlinux=1
-CPPFLAGS = ${BASEFLAGS} ${ARCHFLAG} -O2 -w -I"${METAMOD_SRCDIR}" -I"${HLSDK_BASEDIR}/common" -I"${HLSDK_BASEDIR}/dlls" -I"${HLSDK_BASEDIR}/engine" -I"${HLSDK_BASEDIR}/pm_shared" -I"${HLSDK_BASEDIR}/public"
+CPPFLAGS = ${BASEFLAGS} ${ARCHFLAG} -O2 -mtune=generic -march=i686 -mmmx -msse -msse2 -O2 -mfpmath=sse -s \
+ -Wno-write-strings -Wno-attributes -std=gnu++14 -static-libstdc++ -shared-libgcc \
+ -I"${META_DIR}" -I"${HLSDK_DIR}/common" -I"${HLSDK_DIR}/dlls" \
+ -I"${HLSDK_DIR}/engine" -I"${HLSDK_DIR}/pm_shared" -I"${HLSDK_DIR}/public"
OBJ = NodeMachine.o \
bot.o \
@@ -30,7 +32,7 @@ ifeq ($(UNAME_S),Darwin)
SO_SUFFIX = dylib
endif
-realbot_mm_i386.${SO_SUFFIX}: ${OBJ}
+realbot_mm.${SO_SUFFIX}: ${OBJ}
${CPP} ${ARCHFLAG} -fPIC -shared -o $@ ${OBJ} -ldl
mkdir -p Release
mv $@ ${OBJ} Release
diff --git a/Makefile.debug b/Makefile.debug
index 76c7fdb..557630d 100644
--- a/Makefile.debug
+++ b/Makefile.debug
@@ -5,7 +5,7 @@ ARCHFLAG = -m32 -g
METAMOD_SRCDIR = ./dependencies/metamod-hl1/metamod
HLSDK_BASEDIR = ./dependencies/hlsdk
-BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -Dlinux=1 -g
+BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -Dlinux=1 -ggdb3
CPPFLAGS = ${BASEFLAGS} ${ARCHFLAG} -O0 -w -I"${METAMOD_SRCDIR}" -I"${HLSDK_BASEDIR}/common" -I"${HLSDK_BASEDIR}/dlls" -I"${HLSDK_BASEDIR}/engine" -I"${HLSDK_BASEDIR}/pm_shared" -I"${HLSDK_BASEDIR}/public"
OBJ = NodeMachine.o \
@@ -30,7 +30,7 @@ ifeq ($(UNAME_S),Darwin)
SO_SUFFIX = dylib
endif
-realbot_mm_i386.${SO_SUFFIX}: ${OBJ}
+realbot_mm.${SO_SUFFIX}: ${OBJ}
${CPP} ${ARCHFLAG} -fPIC -shared -o $@ ${OBJ} -ldl
mkdir -p Release
mv $@ ${OBJ} Release
diff --git a/NodeDataTypes.h b/NodeDataTypes.h
index dab5cd8..5b00242 100644
--- a/NodeDataTypes.h
+++ b/NodeDataTypes.h
@@ -6,7 +6,7 @@
**
* DISCLAIMER
*
- * History, Information & Credits:
+ * History, Information & Credits:
* RealBot is based partially upon the HPB-Bot Template #3 by Botman
* Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
* Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
@@ -18,178 +18,235 @@
*
* Pierre Marie Baty
* Count-Floyd
- *
+ *
* !! BOTS-UNITED FOREVER !!
- *
+ *
* This project is open-source, it is protected under the GPL license;
* By using this source-code you agree that you will ALWAYS release the
* source-code with your project.
*
**/
-/**
- * NODE MACHINE data types
- * COPYRIGHTED BY STEFAN HENDRIKS (C)
- **/
+ /**
+ * NODE MACHINE data types
+ * COPYRIGHTED BY STEFAN HENDRIKS (C)
+ **/
#ifndef NODEDATATYPES_H
#define NODEDATATYPES_H
+#include
+#include
+
// player sizes for path_connection_walkable
-#define MAX_JUMPHEIGHT 60 // confirmed // 45 without crouching
-#define MAX_FALLHEIGHT 130 // not confirmed (200 is to high, adjusted)
-#define MAX_STAIRHEIGHT 18 // confirmed
-#define HEAD_HEIGHT 72 // confirmed
-#define ORIGIN_HEIGHT 36 // confirmed (?)
-#define CROUCHED_HEIGHT 37 // confirmed
-#define PLAYER_WIDTH 32 // confirmed (?)
+enum : std::uint8_t
+{
+ MAX_JUMPHEIGHT = 60, // confirmed // 45 without crouching
+ MAX_FALLHEIGHT = 130, // not confirmed (200 is to high, adjusted)
+ MAX_STAIRHEIGHT = 18, // confirmed
+ HEAD_HEIGHT = 72, // confirmed
+ ORIGIN_HEIGHT = 36, // confirmed (?)
+ CROUCHED_HEIGHT = 37, // confirmed
+ PLAYER_WIDTH = 32 // confirmed (?)
+};
// File version
// Version 1.0
-#define FILE_NODE_VER1 1
-#define FILE_EXP_VER1 1
+enum : std::uint8_t
+{
+ FILE_NODE_VER1 = 1,
+ FILE_EXP_VER1 = 1
+};
// Version 2.0
-#define FILE_NODE_VER2 2
-#define FILE_EXP_VER2 2
+enum : std::uint8_t
+{
+ FILE_NODE_VER2 = 2,
+ FILE_EXP_VER2 = 2
+};
// Node bits (for navigational performance)
-#define BIT_LADDER (1 << 0)
-#define BIT_WATER (1 << 1)
-#define BIT_JUMP (1 << 2)
-#define BIT_DUCK (1 << 3)
+enum : std::uint8_t
+{
+ BIT_LADDER = (1 << 0),
+ BIT_WATER = (1 << 1),
+ BIT_JUMP = (1 << 2),
+ BIT_DUCK = (1 << 3),
+ BIT_DUCKJUMP = (1 << 4)
+};
// Path flags
-#define PATH_DANGER 39 // Picked a random number here
-#define PATH_CONTACT 37 // w0h00
-#define PATH_NONE 32 // - rushing
-#define PATH_CAMP 31 // camp path
+enum : std::uint8_t
+{
+ PATH_DANGER = 39, // Picked a random number here
+ PATH_CONTACT = 37, // w0h00
+ PATH_NONE = 32, // - rushing
+ PATH_CAMP = 31 // camp path
+};
// Visibility flags
-#define VIS_INVALID 96 // BERKED
-#define VIS_UNKNOWN 97
-#define VIS_VISIBLE 98
-#define VIS_BLOCKED 99
+enum : std::uint8_t
+{
+ VIS_INVALID = 96, // BERKED
+ VIS_UNKNOWN = 97,
+ VIS_VISIBLE = 98,
+ VIS_BLOCKED = 99
+};
// Goal types & info
-#define MAX_GOALS 75
+constexpr int MAX_GOALS = 75;
// Node types / goal types
-#define GOAL_SPAWNCT 1
-#define GOAL_SPAWNT 2
-#define GOAL_BOMBSPOT 3
-#define GOAL_BOMB 4 // updates all the time
-#define GOAL_HOSTAGE 5 // updates all the time
-#define GOAL_RESCUEZONE 6 // rescue zone (for hostages)
-#define GOAL_CONTACT 7 // zones where teams often have contact
-#define GOAL_IMPORTANT 8
-#define GOAL_VIP 9 // as_ maps VIP starting point
-#define GOAL_VIPSAFETY 10 // as_ maps VIP safety zone
-#define GOAL_ESCAPEZONE 11 // es_ maps escape zone
-#define GOAL_WEAPON 12 // pre-dropped weapons like in awp_map
-#define GOAL_NONE 99
+enum : std::uint8_t
+{
+ GOAL_SPAWNCT = 1,
+ GOAL_SPAWNT = 2,
+ GOAL_BOMBSPOT = 3,
+ GOAL_BOMB = 4, // updates all the time
+ GOAL_HOSTAGE = 5, // updates all the time
+ GOAL_RESCUEZONE = 6, // rescue zone (for hostages)
+ GOAL_CONTACT = 7, // zones where teams often have contact
+ GOAL_IMPORTANT = 8, // important goals
+ GOAL_VIP = 9, // as_ maps VIP starting point
+ GOAL_VIPSAFETY = 10, // as_ maps VIP safety zone
+ GOAL_ESCAPEZONE = 11, // es_ maps escape zone
+ GOAL_WEAPON = 12, // pre-dropped weapons like in awp_map
+ GOAL_NONE = 99
+};
// Node costs
-#define NODE_DANGER 8192 // Value
-#define NODE_DANGER_STEP 0.5 // Step to take to get dangerous
-#define NODE_DANGER_DIST 512.0 // Distance
+enum : std::uint16_t
+{
+ NODE_DANGER = 8192 // Value
+};
+
+constexpr float NODE_DANGER_STEP = 0.5f; // Step to take to get dangerous;
+constexpr float NODE_DANGER_DIST = 512.0f; // Distance;
// Node contact costs
-#define NODE_CONTACT 8192
-#define NODE_CONTACT_STEP 0.2
-#define NODE_CONTACT_DIST 128
+enum : std::uint16_t
+{
+ NODE_CONTACT = 8192
+};
+
+constexpr float NODE_CONTACT_STEP = 0.2f;
+
+enum : std::uint8_t
+{
+ NODE_CONTACT_DIST = 128
+};
// Node boundries
-#define MAX_NODES 4096
-#define MAX_NEIGHBOURS 16
-#define NODE_ZONE 45
+enum : std::uint8_t
+{
+ NODE_ZONE = 45 // Maybe increase it to 128 or 144 to reduce the amount of excess nodes [APG]RoboCop[CL]
+};
+
+constexpr int MAX_NODES = 4096;
+constexpr int MAX_NEIGHBOURS = 16; // Maybe increase it to 128 or 144 to reduce the amount of excess nodes [APG]RoboCop[CL]
+
#define MAX_PATH_NODES MAX_NODES
// Max troubled node connections we remember
-#define MAX_TROUBLE 100
+constexpr int MAX_TROUBLE = 100;
// Meridian stuff
-#define SIZE_MEREDIAN 256
-#define MAP_MAX_SIZE 16384
-#define MAX_MEREDIANS MAP_MAX_SIZE / SIZE_MEREDIAN // Size of HL map divided by SIZE of a meridian to evenly spread
-#define MAX_NODES_IN_MEREDIANS 120 // EVY: higher number, number of nodes per meredian
+enum : std::uint16_t
+{
+ SIZE_MEREDIAN = 256,
+ MAP_MAX_SIZE = 16384
+};
+
+#define MAX_MEREDIANS (MAP_MAX_SIZE / SIZE_MEREDIAN) // Size of HL map divided by SIZE of a meridian to evenly spread
+constexpr int MAX_NODES_IN_MEREDIANS = 120; // EVY: higher number, number of nodes per meredian;
//#define MAX_NODES_IN_MEREDIANS 80 // (size meredian / zone (~6) times 2 (surface) , rounded to 80
// A* defines OPEN/CLOSED lists
-#define OPEN 1 // open, can still re-evaluate
-#define CLOSED 2 // closed, do nothing with it
-#define AVAILABLE 3 // available, may open
+enum : std::uint8_t
+{
+ OPEN = 1, // open, can still re-evaluate
+ CLOSED = 2, // closed, do nothing with it
+ AVAILABLE = 3 // available, may open
+};
-const unsigned long g_iMaxVisibilityByte = (MAX_NODES * MAX_NODES) / 8;
+constexpr unsigned long g_iMaxVisibilityByte = MAX_NODES * MAX_NODES / 8;
// doors (doors.cpp) HLSDK
-#define SF_DOOR_ROTATE_Y 0
-#define SF_DOOR_START_OPEN 1
-#define SF_DOOR_ROTATE_BACKWARDS 2
-#define SF_DOOR_PASSABLE 8
-#define SF_DOOR_ONEWAY 16
-#define SF_DOOR_NO_AUTO_RETURN 32
-#define SF_DOOR_ROTATE_Z 64
-#define SF_DOOR_ROTATE_X 128
-#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button.
-#define SF_DOOR_NOMONSTERS 512 // Monster can't open
-#define SF_DOOR_SILENT 0x80000000
-
+enum : std::uint16_t
+{
+ SF_DOOR_ROTATE_Y = 0,
+ SF_DOOR_START_OPEN = 1,
+ SF_DOOR_ROTATE_BACKWARDS = 2,
+ SF_DOOR_PASSABLE = 8,
+ SF_DOOR_ONEWAY = 16,
+ SF_DOOR_NO_AUTO_RETURN = 32,
+ SF_DOOR_ROTATE_Z = 64,
+ SF_DOOR_ROTATE_X = 128,
+ SF_DOOR_USE_ONLY = 256, // door must be opened by player's use button.
+ SF_DOOR_NOMONSTERS = 512 // Monster can't open
+};
+
+constexpr unsigned SF_DOOR_SILENT = 0x80000000;
// Player information on map
typedef struct {
- Vector vPrevPos; // Previous Position
- int iNode; // Previous Node
+ Vector vPrevPos; // Previous Position
+ int iNode; // Previous Node
}
- tPlayer;
+tPlayer;
// Astar Node informaiton
-typedef struct {
- int state; // OPEN/CLOSED
- double cost; // Cost
- double danger;
- int parent; // Who opened this node?
-}
- tNodestar;
+typedef struct tNodestar {
+ int state; // OPEN/CLOSED
+ int parent; // Who opened this node?
+ float cost; // Cost
+ double danger;
+
+ // Comparison operator for priority queue
+ bool operator<(const tNodestar& other) const {
+ return cost > other.cost; // Note: Use '>' for min-heap (lower cost has higher priority)
+ }
+} tNodestar;
// Additional Node Information
typedef struct {
- float fDanger[2]; // Danger information (0.0 - no danger, 1.0 dangerous). Indexed per team (T/CT)
- float fContact[2]; // How many times have contact with enemy (0.0 none, 1.0 , a lot)
+ float fDanger[2]; // Danger information (0.0 - no danger, 1.0 dangerous). Indexed per team (T/CT)
+ float fContact[2]; // How many times have contact with enemy (0.0 none, 1.0 , a lot)
}
- tInfoNode;
+tInfoNode;
typedef struct {
- int iNodes[MAX_NODES_IN_MEREDIANS];
+ int iNodes[MAX_NODES_IN_MEREDIANS];
}
- tMeredian;
+tMeredian;
// Trouble connections
typedef struct {
- int iFrom; // From NODE
- int iTo; // To NODE
- int iTries; // How many times we had trouble with this connection
+ int iFrom; // From NODE
+ int iTo; // To NODE
+ int iTries; // How many times we had trouble with this connection
}
- tTrouble;
+tTrouble;
// Node (stored in RBN file, do not change casually)
typedef struct {
- Vector origin; // Node origin
- int iNeighbour[MAX_NEIGHBOURS]; // Reachable nodes for this node
- int iNodeBits;
+ Vector origin; // Node origin
+ std::array iNeighbour; // Reachable nodes for this node
+ int iNodeBits;
+ int index;
}
- tNode;
+tNode;
// Goal Node information
typedef struct {
- edict_t *pGoalEdict; // edict of goal
- int iNode; // index of node attached to it
- int iType; // type of goal
- int iChecked; // many times checked/visited?
- int iBadScore; // bad score for a node (when it seems to be unreachable?)
- int index; // the index in the Goals[] array
- char name[32]; // name of goal
+ edict_t* pGoalEdict; // edict of goal
+ int iNode; // index of node attached to it
+ int iType; // type of goal
+ int iChecked; // many times checked/visited?
+ int iBadScore; // bad score for a node (when it seems to be unreachable?)
+ int index; // the index in the Goals[] array
+ char name[32]; // name of goal
}
- tGoal;
+tGoal;
#endif // NODEDATATYPES_H
diff --git a/NodeMachine.cpp b/NodeMachine.cpp
index b65362e..0e6d352 100644
--- a/NodeMachine.cpp
+++ b/NodeMachine.cpp
@@ -1,3 +1,5 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check it.
+// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
/**
* RealBot : Artificial Intelligence
* Version : Work In Progress
@@ -6,7 +8,7 @@
**
* DISCLAIMER
*
- * History, Information & Credits:
+ * History, Information & Credits:
* RealBot is based partially upon the HPB-Bot Template #3 by Botman
* Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
* Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
@@ -18,9 +20,9 @@
*
* Pierre Marie Baty
* Count-Floyd
- *
+ *
* !! BOTS-UNITED FOREVER !!
- *
+ *
* This project is open-source, it is protected under the GPL license;
* By using this source-code you agree that you will ALWAYS release the
* source-code with your project.
@@ -32,14 +34,18 @@
* COPYRIGHTED BY STEFAN HENDRIKS (C) 2003-2004
**/
-#include
+#include
+#include
+#include
+#include
#include
#include
#include
#include
// malloc stuff?
-#include "stdlib.h"
+#include
+#include
// ---
#include "bot.h"
@@ -52,9 +58,9 @@
tNodestar astar_list[MAX_NODES];
-const Vector &INVALID_VECTOR = Vector(9999, 9999, 9999);
+const Vector& INVALID_VECTOR = Vector(9999, 9999, 9999);
-extern edict_t *pHostEdict;
+extern edict_t* pHostEdict;
extern cGame Game;
extern cBot bots[32];
extern int draw_nodepath;
@@ -62,72 +68,61 @@ extern int draw_nodepath;
//---------------------------------------------------------
//CODE: CHEESEMONSTER
-int // BERKED
-cNodeMachine::GetVisibilityFromTo(int iFrom, int iTo) {
- // prevent negative indexes on iVisChecked below -- BERKED
- if (iFrom < 0 || iFrom > MAX_NODES || iTo < 0 || iTo > MAX_NODES) {
- return VIS_INVALID;
+int cNodeMachine::GetVisibilityFromTo(const int iFrom, const int iTo) const {
+ if (iFrom < 0 || iFrom >= MAX_NODES || iTo < 0 || iTo >= MAX_NODES) {
+ rblog("ERROR: Index out of bounds in GetVisibilityFromTo! Returning VIS_BLOCKED\n");
+ return VIS_BLOCKED;
+ }
+
+ if (iVisChecked[iFrom] == 0) {
+ return VIS_UNKNOWN;
}
- // -- BY STEFAN --
- if (iVisChecked[iFrom] == 0)
- return VIS_UNKNOWN; // we have no clue
- // -- END --
// was int
// work out the position
- long iPosition = (iFrom * MAX_NODES) + iTo;
-
- long iByte = (int) (iPosition / 8);
- unsigned int iBit = iPosition % 8;
+ const long iPosition = iFrom * MAX_NODES + iTo;
+ const long iByte = iPosition / 8;
+ const unsigned int iBit = iPosition % 8;
- if (iByte < g_iMaxVisibilityByte) {
- // Get the Byte that this is in
- unsigned char *ToReturn = (cVisTable + iByte);
- // get the bit in the byte
- return ((*ToReturn & (1 << iBit)) > 0) ? VIS_VISIBLE : VIS_BLOCKED; // BERKED
- }
+ // Optional assertion
+ assert(iByte < g_iMaxVisibilityByte);
+ const unsigned char ToReturn = cVisTable[iByte];
- return VIS_BLOCKED; // BERKED
+ return (ToReturn & (1 << iBit)) ? VIS_VISIBLE : VIS_BLOCKED;
}
-void
-cNodeMachine::SetVisibilityFromTo(int iFrom, int iTo, bool bVisible) {
- // prevent negative indexes on iVisChecked below, fixing SEGV -- BERKED
- if (iFrom < 0 || iFrom > MAX_NODES || iTo < 0 || iTo > MAX_NODES) {
+void cNodeMachine::SetVisibilityFromTo(const int iFrom, const int iTo, const bool bVisible) {
+ if (iFrom < 0 || iFrom >= MAX_NODES || iTo < 0 || iTo >= MAX_NODES) {
+ rblog("ERROR: Index out of bounds in SetVisibilityFromTo!\n");
return;
}
- // -- STEFAN --
- iVisChecked[iFrom] = 1; // WE HAVE CHECKED THIS ONE
- // -- END --
+ iVisChecked[iFrom] = 1;
- // was int
- long iPosition = (iFrom * MAX_NODES) + iTo;
-
- long iByte = (int) (iPosition / 8);
- unsigned int iBit = iPosition % 8;
-
- if (iByte < g_iMaxVisibilityByte) {
- unsigned char *ToChange = (cVisTable + iByte);
+ // work out the position
+ const long iPosition = iFrom * MAX_NODES + iTo;
+ const long iByte = iPosition / 8;
+ const unsigned int iBit = iPosition % 8;
- if (bVisible)
- *ToChange |= (1 << iBit);
- else
- *ToChange &= ~(1 << iBit);
+ // Optional assertion
+ assert(iByte < g_iMaxVisibilityByte);
+ unsigned char& ToChange = cVisTable[iByte];
+ if (bVisible) {
+ ToChange |= (1 << iBit);
+ }
+ else {
+ ToChange &= ~(1 << iBit);
}
}
-void cNodeMachine::ClearVisibilityTable(void) {
- if (cVisTable) {
- memset(cVisTable, 0, g_iMaxVisibilityByte);
- }
+void cNodeMachine::ClearVisibilityTable()
+{
+ std::fill(cVisTable.begin(), cVisTable.end(), 0);
}
-void cNodeMachine::FreeVisibilityTable(void) {
- if (cVisTable) {
- free(cVisTable);
- }
+void cNodeMachine::FreeVisibilityTable() {
+ cVisTable.clear();
}
//---------------------------------------------------------
@@ -137,56 +132,72 @@ void cNodeMachine::init() {
rblog("cNodeMachine::init() - START\n");
iMaxUsedNodes = 0;
- for (int i = 0; i < MAX_NODES; i++) {
- // --- nodes
- Nodes[i].origin = Vector(9999, 9999, 9999);
- for (int n = 0; n < MAX_NEIGHBOURS; n++)
- Nodes[i].iNeighbour[n] = -1;
+ initNodes();
+ initInfoNodes();
+ initTroubles();
+ initGoals();
+ initPaths();
+ initVisTable();
+ initMeredians();
- // No bits set
- Nodes[i].iNodeBits = 0;
+ rblog("cNodeMachine::init() - END\n");
+}
- // --- info nodes
- for (int d = 0; d < 2; d++) {
- InfoNodes[i].fDanger[d] = 0.0;
- }
+void cNodeMachine::initNodes() {
+ int currentIndex = 0;
+ for (tNode& node : Nodes) {
+ node.origin = INVALID_VECTOR;
+ std::fill(node.iNeighbour.begin(), node.iNeighbour.end(), -1);
+ node.iNodeBits = 0;
+ node.index = currentIndex++;
}
+}
- // Init trouble
- for (int t = 0; t < MAX_TROUBLE; t++) {
- Troubles[t].iFrom = -1;
- Troubles[t].iTo = -1;
- Troubles[t].iTries = -1;
+void cNodeMachine::initInfoNodes() {
+ for (tInfoNode& infoNode : InfoNodes) {
+ std::fill(std::begin(infoNode.fDanger), std::end(infoNode.fDanger), 0.0f);
+ std::fill(std::begin(infoNode.fContact), std::end(infoNode.fContact), 0.0f);
}
+}
- initGoals();
+void cNodeMachine::initializeNode(tNode& node) {
+ node.origin = INVALID_VECTOR;
+ std::fill(std::begin(node.iNeighbour), std::end(node.iNeighbour), -1);
+ node.iNodeBits = 0;
+ std::fill(std::begin(InfoNodes[node.index].fDanger), std::end(InfoNodes[node.index].fDanger), 0.0f);
+}
- // Init paths
- for (int p = 0; p < MAX_BOTS; p++)
- path_clear(p);
+void cNodeMachine::initTroubles() {
+ for (tTrouble& Trouble : Troubles) {
+ Trouble.iFrom = -1;
+ Trouble.iTo = -1;
+ Trouble.iTries = -1;
+ }
+}
- // Init VisTable
- for (int iVx = 0; iVx < MAX_NODES; iVx++) {
- iVisChecked[iVx] = 0; // not checked yet
+void cNodeMachine::initPaths() {
+ for (int p = 0; p < MAX_BOTS; p++) {
+ path_clear(p);
}
+}
+
+void cNodeMachine::initVisTable() {
+ std::fill(std::begin(iVisChecked), std::end(iVisChecked), 0);
// CODE: From cheesemonster
- unsigned long iSize = g_iMaxVisibilityByte;
+ constexpr unsigned long iSize = g_iMaxVisibilityByte;
//create a heap type thing...
- FreeVisibilityTable(); // 16/07/04 - free it first
- cVisTable = (unsigned char *) malloc(iSize);
- memset(cVisTable, 0, iSize);
+ cVisTable.resize(iSize);
ClearVisibilityTable();
- // END:
-
- // Init Meredians
- for (int iMx = 0; iMx < MAX_MEREDIANS; iMx++)
- for (int iMy = 0; iMy < MAX_MEREDIANS; iMy++)
- for (int iNode = 0; iNode < MAX_NODES_IN_MEREDIANS; iNode++)
- Meredians[iMx][iMy].iNodes[iNode] = -1;
+}
- rblog("cNodeMachine::init() - END\n");
+void cNodeMachine::initMeredians() {
+ for (tMeredian (&Meredian)[64] : Meredians) {
+ for (tMeredian& iMy : Meredian) {
+ std::fill(std::begin(iMy.iNodes), std::end(iMy.iNodes), -1);
+ }
+ }
}
void cNodeMachine::initGoals() {
@@ -196,44 +207,32 @@ void cNodeMachine::initGoals() {
}
}
-void cNodeMachine::initGoal(int g) {
+void cNodeMachine::initGoal(const int g) {
Goals[g].iNode = -1;
- Goals[g].pGoalEdict = NULL;
+ Goals[g].pGoalEdict = nullptr;
Goals[g].iType = GOAL_NONE;
Goals[g].index = g;
Goals[g].iChecked = 0;
Goals[g].iBadScore = 0; // no bad score at init
- memset(Goals[g].name, 0, sizeof(Goals[g].name));
+ std::memset(Goals[g].name, 0, sizeof(Goals[g].name));
}
-int cNodeMachine::GetTroubleIndexForConnection(int iFrom, int iTo) {
- char msg[255];
-// sprintf(msg, "GetTroubleIndexForConnection | from %d to %d\n", iFrom, iTo);
-// rblog(msg);
- // in case of invalid values, return -1 - no need to loop
- if (iFrom < -1 || iFrom >= MAX_NODES) {
- rblog("GetTroubleIndexForConnection | invalid iFrom\n");
- return -1;
- }
- if (iTo < -1 || iTo >= MAX_NODES) {
- rblog("GetTroubleIndexForConnection | invalid iTo\n");
+int cNodeMachine::GetTroubleIndexForConnection(int iFrom, int iTo) const
+{
+ if (iFrom < 0 || iFrom >= MAX_NODES || iTo < 0 || iTo >= MAX_NODES) {
return -1;
}
- // seems to be valid, look for troubled connections
- int index;
- for (index = 0; index < MAX_TROUBLE; index++) {
- if (Troubles[index].iFrom == iFrom &&
- Troubles[index].iTo == iTo) {
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "GetTroubleIndexForConnection | Found index [%d] for from %d to %d\n", index, iFrom, iTo);
- rblog(msg);
- // found troubled connection, return its index
- return index;
- }
+ const tTrouble* it = std::find_if(std::begin(Troubles), std::end(Troubles),
+ [iFrom, iTo](const tTrouble& trouble)
+ {
+ return trouble.iFrom == iFrom && trouble.iTo == iTo;
+ });
+
+ if (it != std::end(Troubles)) {
+ return std::distance(std::begin(Troubles), it);
}
-// rblog("GetTroubleIndexForConnection | found no index matching from/to. Returning -1\n");
return -1;
}
@@ -244,15 +243,15 @@ int cNodeMachine::GetTroubleIndexForConnection(int iFrom, int iTo) {
* @param iTo
* @return index of newly created index
*/
-int cNodeMachine::AddTroubledConnection(int iFrom, int iTo) {
- int existingIndex = GetTroubleIndexForConnection(iFrom, iTo);
+int cNodeMachine::AddTroubledConnection(const int iFrom, const int iTo)
+{
+ const int existingIndex = GetTroubleIndexForConnection(iFrom, iTo);
if (existingIndex > -1)
return existingIndex; // already exists
int iNew = -1;
- int t;
- for (t = 0; t < MAX_TROUBLE; t++)
+ for (int t = 0; t < MAX_TROUBLE; t++)
if (Troubles[t].iFrom < 0 ||
Troubles[t].iTo < 0) {
iNew = t;
@@ -270,16 +269,17 @@ int cNodeMachine::AddTroubledConnection(int iFrom, int iTo) {
return iNew;
}
-bool cNodeMachine::hasAttemptedConnectionTooManyTimes(int index) {
- if (index < 0) {
+bool cNodeMachine::hasAttemptedConnectionTooManyTimes(const int index) const
+{
+ if (index < 0 || index >= MAX_TROUBLE) { // Use MAX_TROUBLE for bounds checking [APG]RoboCop[CL]
rblog("(trouble) hasAttemptedConnectionTooManyTimes | invalid index for hasAttemptedConnectionTooManyTimes()\n");
// deal with invalid connection
return false;
}
- tTrouble &trouble = Troubles[index];
+ const tTrouble& trouble = Troubles[index];
char msg[255];
- sprintf(msg, "(trouble) hasAttemptedConnectionTooManyTimes | Connection %d (%d->%d) has %d tries.\n", index, trouble.iFrom, trouble.iTo, trouble.iTries);
+ snprintf(msg, sizeof(msg), "(trouble) hasAttemptedConnectionTooManyTimes | Connection %d (%d->%d) has %d tries.\n", index, trouble.iFrom, trouble.iTo, trouble.iTries);
rblog(msg);
if (trouble.iTries > 2) {
@@ -298,8 +298,9 @@ bool cNodeMachine::hasAttemptedConnectionTooManyTimes(int index) {
* @param iTo
* @return
*/
-bool cNodeMachine::IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded(int iFrom, int iTo) {
- int index = AddTroubledConnection(iFrom, iTo);
+bool cNodeMachine::IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded(const int iFrom, const int iTo)
+{
+ const int index = AddTroubledConnection(iFrom, iTo);
IncreaseAttemptsForTroubledConnection(index);
if (hasAttemptedConnectionTooManyTimes(index)) {
rblog("(trouble) IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded | a troubled connection - tried too many times!\n");
@@ -312,37 +313,37 @@ bool cNodeMachine::IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded(int i
}
return false;
- } else {
- rblog("(trouble) IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded | may attempt another time\n");
- return true;
}
+ rblog("(trouble) IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded | may attempt another time\n");
+ return true;
}
-void cNodeMachine::IncreaseAttemptsForTroubledConnection(int index) {
+void cNodeMachine::IncreaseAttemptsForTroubledConnection(const int index)
+{
if (index < 0 || index >= MAX_TROUBLE) return;
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "(trouble) IncreaseAttemptsForTroubledConnection | Increasing trouble for connection [%d]\n", index);
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "(trouble) IncreaseAttemptsForTroubledConnection | Increasing trouble for connection [%d]\n", index);
rblog(msg);
Troubles[index].iTries++;
- tTrouble &trouble = Troubles[index];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "(trouble) IncreaseAttemptsForTroubledConnection | Connection %d (%d->%d) has %d tries.\n", index, trouble.iFrom, trouble.iTo, trouble.iTries);
+ const tTrouble &trouble = Troubles[index];
+ std::memset(msg, 0, sizeof(msg));
+ snprintf(msg, sizeof(msg), "(trouble) IncreaseAttemptsForTroubledConnection | Connection %d (%d->%d) has %d tries.\n", index, trouble.iFrom, trouble.iTo, trouble.iTries);
rblog(msg);
}
-bool cNodeMachine::ClearTroubledConnection(int iFrom, int iTo) {
+bool cNodeMachine::ClearTroubledConnection(const int iFrom, const int iTo)
+{
char msg[255];
- sprintf(msg, "(trouble) NodeMachine::ClearTroubledConnection | %d -> %d - START\n", iFrom, iTo);
+ snprintf(msg, sizeof(msg), "(trouble) NodeMachine::ClearTroubledConnection | %d -> %d - START\n", iFrom, iTo);
rblog(msg);
- int index = GetTroubleIndexForConnection(iFrom, iTo);
+ const int index = GetTroubleIndexForConnection(iFrom, iTo);
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "(trouble) NodeMachine::ClearTroubledConnection | %d -> %d has index %d\n", iFrom, iTo, index);
+ std::memset(msg, 0, sizeof(msg));
+ snprintf(msg, sizeof(msg), "(trouble) NodeMachine::ClearTroubledConnection | %d -> %d has index %d\n", iFrom, iTo, index);
rblog(msg);
if (index < 0) {
@@ -358,36 +359,40 @@ bool cNodeMachine::ClearTroubledConnection(int iFrom, int iTo) {
return true;
}
-void cNodeMachine::path_clear(int botIndex) {
+void cNodeMachine::path_clear(const int botIndex)
+{
for (int nodeIndex = 0; nodeIndex < MAX_NODES; nodeIndex++) {
iPath[botIndex][nodeIndex] = -1;
}
}
// Return
-Vector cNodeMachine::node_vector(int iNode) {
+Vector cNodeMachine::node_vector(const int iNode) const
+{
if (iNode > -1) {
return Nodes[iNode].origin;
}
- return Vector(9999, 9999, 9999);
+ return {9999, 9999, 9999};
}
// Input: Vector, Output X and Y Meredians
-void cNodeMachine::VectorToMeredian(Vector vOrigin, int *iX, int *iY) {
+void cNodeMachine::VectorToMeredian(const Vector& vOrigin, int *iX, int *iY)
+{
// Called for lookupt and for storing
- float iCoordX = vOrigin.x + 8192.0; // map height (converts from - to +)
- float iCoordY = vOrigin.y + 8192.0; // map width (converts from - to +)
+ float iCoordX = vOrigin.x + 8192.0f; // map height (converts from - to +)
+ float iCoordY = vOrigin.y + 8192.0f; // map width (converts from - to +)
// Meredian:
- iCoordX = iCoordX / SIZE_MEREDIAN;
- iCoordY = iCoordY / SIZE_MEREDIAN;
+ iCoordX = iCoordX / static_cast(SIZE_MEREDIAN);
+ iCoordY = iCoordY / static_cast(SIZE_MEREDIAN);
- *iX = (int) iCoordX;
- *iY = (int) iCoordY;
+ *iX = static_cast(iCoordX);
+ *iY = static_cast(iCoordY);
}
-void cNodeMachine::AddToMeredian(int iX, int iY, int iNode) {
+void cNodeMachine::AddToMeredian(const int iX, const int iY, const int iNode)
+{
int index = -1;
for (int i = 0; i < MAX_NODES_IN_MEREDIANS; i++)
if (Meredians[iX][iY].iNodes[i] < 0) {
@@ -402,9 +407,10 @@ void cNodeMachine::AddToMeredian(int iX, int iY, int iNode) {
}
// Does the node float?
-bool cNodeMachine::node_float(Vector vOrigin, edict_t *pEdict) {
+bool cNodeMachine::node_float(const Vector& vOrigin, edict_t *pEdict)
+{
TraceResult tr;
- Vector tr_end = vOrigin - Vector(0, 0, (ORIGIN_HEIGHT * 1.2));
+ const Vector tr_end = vOrigin - Vector(0, 0, static_cast(ORIGIN_HEIGHT) * 1.2f);
//Using TraceHull to detect de_aztec bridge and other entities. (skill self)
//UTIL_TraceHull(vOrigin, tr_end, ignore_monsters, point_hull, pEdict->v.pContainingEntity, &tr);
@@ -412,50 +418,51 @@ bool cNodeMachine::node_float(Vector vOrigin, edict_t *pEdict) {
UTIL_TraceHull(vOrigin, tr_end, ignore_monsters, human_hull,
pEdict->v.pContainingEntity, &tr);
else
- UTIL_TraceHull(vOrigin, tr_end, ignore_monsters, human_hull, NULL,
+ UTIL_TraceHull(vOrigin, tr_end, ignore_monsters, human_hull, nullptr,
&tr);
// if nothing hit: floating too high, return false
- if (tr.flFraction >= 1.0)
+ if (tr.flFraction >= 1.0f)
return true; // floating
// *NOTE*: Actually this check should not be nescesary!
- if (tr.flFraction < 1.0)
+ if (tr.flFraction < 1.0f)
if (tr.pHit == pEdict)
return true;
// if inside wall: return false
if (tr.fStartSolid == 1) {
- // todo: make sure the node does not start within this wall
- return false; // not floating
+ rblog("(node) node_float | node is inside wall!\n");
+ return false;
}
return false; // not floating
}
// Does the node stand on a crate? or a steep slope?
-bool cNodeMachine::node_on_crate(Vector vOrigin, edict_t *pEdict) {
+bool cNodeMachine::node_on_crate(const Vector& vOrigin, edict_t *pEdict)
+{
TraceResult tr;
- Vector tr_end = vOrigin - Vector(0, 0, (ORIGIN_HEIGHT * 1.2));
+ const Vector tr_end = vOrigin - Vector(0, 0, static_cast(ORIGIN_HEIGHT) * 1.2f);
//Using TraceHull to detect de_aztec bridge and other entities. (skill self)
if (pEdict)
UTIL_TraceHull(vOrigin, tr_end, ignore_monsters, human_hull,
pEdict->v.pContainingEntity, &tr);
else
- UTIL_TraceHull(vOrigin, tr_end, ignore_monsters, human_hull, NULL,
+ UTIL_TraceHull(vOrigin, tr_end, ignore_monsters, human_hull, nullptr,
&tr);
// if nothing hit: floating too high, return false
- if (tr.flFraction >= 1.0)
+ if (tr.flFraction >= 1.0f)
return false;
// hit something
- if (tr.flFraction < 1.0) {
+ if (tr.flFraction < 1.0f) {
// thanks a million to PMB , so i know what the difference
// is between something straight (crate) and steep... although i have
// no clue yet how to compute these values myself.
- if ( /*tr.vecPlaneNormal.z >= 0.7 && */ tr.vecPlaneNormal.z == 1.0) {
+ if ( /*tr.vecPlaneNormal.z >= 0.7 && */ tr.vecPlaneNormal.z == 1.0f) {
return true;
}
}
@@ -464,6 +471,46 @@ bool cNodeMachine::node_on_crate(Vector vOrigin, edict_t *pEdict) {
return false;
}
+int cNodeMachine::node_dangerous(const int iTeam, const Vector& vOrigin, const float fMaxDistance) //TODO: Experimental & Incomplete [APG]RoboCop[CL]
+{
+ int iBestNode = -1;
+ float fMaxDanger = 0.0f;
+
+ // Use Meredians to search for nodes
+ int iX, iY;
+ VectorToMeredian(vOrigin, &iX, &iY);
+
+ if (iX < 0 || iY < 0) {
+ return -1; // Invalid coordinates
+ }
+
+ // Search in the current and adjacent meridians to ensure we cover the full radius
+ for (int meredianX = iX - 1; meredianX <= iX + 1; ++meredianX) {
+ for (int meredianY = iY - 1; meredianY <= iY + 1; ++meredianY) {
+ // Ensure meridian coordinates are within bounds
+ if (meredianX < 0 || meredianX >= MAX_MEREDIANS || meredianY < 0 || meredianY >= MAX_MEREDIANS) {
+ continue;
+ }
+
+ for (const int iNode : Meredians[meredianX][meredianY].iNodes) {
+ if (iNode < 0) continue;
+
+ const float fDist = func_distance(vOrigin, Nodes[iNode].origin);
+
+ if (fDist < fMaxDistance) {
+ const float fDanger = InfoNodes[iNode].fDanger[iTeam];
+ if (fDanger > fMaxDanger) {
+ fMaxDanger = fDanger;
+ iBestNode = iNode;
+ }
+ }
+ }
+ }
+ }
+
+ return iBestNode;
+}
+
/**
* Find a node close to vOrigin within distance fDist. Ignoring any pEdict it hits.
* @param vOrigin
@@ -471,7 +518,8 @@ bool cNodeMachine::node_on_crate(Vector vOrigin, edict_t *pEdict) {
* @param pEdict
* @return
*/
-int cNodeMachine::getClosestNode(Vector vOrigin, float fDist, edict_t *pEdict) {
+int cNodeMachine::getClosestNode(const Vector& vOrigin, const float fDist, edict_t *pEdict) const
+{
// REDO: Need faster method to find a node
// TOADD: For secure results all nodes should be checked to figure out the real
// 'closest' node.
@@ -491,14 +539,15 @@ int cNodeMachine::getClosestNode(Vector vOrigin, float fDist, edict_t *pEdict) {
int iCloseNode = -1;
// Search in this meredian
- for (int i = 0; i < MAX_NODES_IN_MEREDIANS; i++) {
- if (Meredians[iX][iY].iNodes[i] < 0) continue; // skip invalid node indexes
+ for (const int i : Meredians[iX][iY].iNodes)
+ {
+ if (i < 0) continue; // skip invalid node indexes
- int iNode = Meredians[iX][iY].iNodes[i];
+ const int iNode = i;
-// if (Nodes[iNode].origin.z > (vOrigin.z + 32)) continue; // do not pick nodes higher than us
+ //if (Nodes[iNode].origin.z > (vOrigin.z + 32)) continue; // do not pick nodes higher than us
- float distanceFromTo = func_distance(vOrigin, Nodes[iNode].origin);
+ const float distanceFromTo = func_distance(vOrigin, Nodes[iNode].origin);
if (distanceFromTo < dist) {
dist = distanceFromTo;
@@ -515,19 +564,13 @@ int cNodeMachine::getClosestNode(Vector vOrigin, float fDist, edict_t *pEdict) {
&tr);
} else {
UTIL_TraceHull(vOrigin, nodeVector, dont_ignore_monsters,
- head_hull, NULL, &tr);
+ head_hull, nullptr, &tr);
}
// if nothing hit:
- if (tr.flFraction >= 1.0) {
- if (pEdict != NULL) {
- if (FInViewCone(&nodeVector, pEdict) // in FOV
- && FVisible(nodeVector, pEdict)) {
- iCloseNode = iNode;
- } else {
- iCloseNode = iNode;
- }
- }
+ if (tr.flFraction >= 1.0f && pEdict != nullptr) {
+ // Regardless of conditions, set iFarNode to iNode
+ iCloseNode = iNode;
}
}
}
@@ -541,7 +584,8 @@ int cNodeMachine::getClosestNode(Vector vOrigin, float fDist, edict_t *pEdict) {
* @param pEdict
* @return
*/
-int cNodeMachine::getFurthestNode(Vector vOrigin, float fDist, edict_t *pEdict) {
+int cNodeMachine::getFurthestNode(const Vector& vOrigin, const float fDist, const edict_t *pEdict) const
+{
// Use Meredians to search for nodes
// TODO: we should take care in the situation where we're at the 'edge' of such a meridian (subspace). So we should
// basicly take edging meridians as well when too close to the edge.
@@ -557,14 +601,15 @@ int cNodeMachine::getFurthestNode(Vector vOrigin, float fDist, edict_t *pEdict)
int iFarNode = -1;
// Search in this meredian
- for (int i = 0; i < MAX_NODES_IN_MEREDIANS; i++) {
- if (Meredians[iX][iY].iNodes[i] < 0) continue; // skip invalid node indexes
+ for (const int i : Meredians[iX][iY].iNodes)
+ {
+ if (i < 0) continue; // skip invalid node indexes
- int iNode = Meredians[iX][iY].iNodes[i];
+ const int iNode = i;
-// if (Nodes[iNode].origin.z > (vOrigin.z + 32)) continue; // do not pick nodes higher than us
+ // if (Nodes[iNode].origin.z > (vOrigin.z + 32)) continue; // do not pick nodes higher than us
- float distanceFromTo = func_distance(vOrigin, Nodes[iNode].origin);
+ const float distanceFromTo = func_distance(vOrigin, Nodes[iNode].origin);
if (distanceFromTo < fDist && // within range
distanceFromTo > dist) { // but furthest so far
dist = distanceFromTo;
@@ -582,19 +627,13 @@ int cNodeMachine::getFurthestNode(Vector vOrigin, float fDist, edict_t *pEdict)
&tr);
} else {
UTIL_TraceHull(vOrigin, nodeVector, dont_ignore_monsters,
- head_hull, NULL, &tr);
+ head_hull, nullptr, &tr);
}
// if nothing hit:
- if (tr.flFraction >= 1.0) {
- if (pEdict != NULL) {
- if (FInViewCone(&nodeVector, pEdict) // in FOV
- && FVisible(nodeVector, pEdict)) {
- iFarNode = iNode;
- } else {
- iFarNode = iNode;
- }
- }
+ if (tr.flFraction >= 1.0f && pEdict != nullptr) {
+ // Regardless of conditions, set iFarNode to iNode
+ iFarNode = iNode;
}
}
}
@@ -602,12 +641,12 @@ int cNodeMachine::getFurthestNode(Vector vOrigin, float fDist, edict_t *pEdict)
}
// Adds a neighbour connection to a node ID
-bool cNodeMachine::add_neighbour_node(int iNode, int iToNode) {
+bool cNodeMachine::add_neighbour_node(const int iNode, const int iToNode) {
if (iNode < 0)
return false;
tNode *node = getNode(iNode);
- int iNeighbourId = freeNeighbourNodeIndex(node);
+ const int iNeighbourId = freeNeighbourNodeIndex(node);
if (iNeighbourId > -1) {
node->iNeighbour[iNeighbourId] = iToNode;
return true;
@@ -623,29 +662,26 @@ bool cNodeMachine::add_neighbour_node(int iNode, int iToNode) {
* @param iTo
* @return
*/
-bool cNodeMachine::removeConnection(int iFrom, int iTo) {
+bool cNodeMachine::removeConnection(const int iFrom, const int iTo) {
if (iFrom < 0 || iTo < 0) {
return false;
}
- char msg[255];
- memset(msg, 0, sizeof(msg));
+ char msg[255] = {};
tNode *node = getNode(iFrom);
if (!node) {
- sprintf(msg, "(trouble) cNodeMachine::removeConnection | From %d, to %d has no node! (error)\n", iFrom, iTo);
+ snprintf(msg, sizeof(msg), "(trouble) cNodeMachine::removeConnection | From %d, to %d has no node! (error)\n", iFrom, iTo);
rblog(msg);
return false;
}
bool removedOneOrMoreNeighbours = false;
- // Find the connection and remove it
- int i = 0;
- for (i = 0; i < MAX_NEIGHBOURS; i++) {
- int neighbourNode = node->iNeighbour[i];
+ for (int i = 0; i < MAX_NEIGHBOURS; i++) {
+ const int neighbourNode = node->iNeighbour[i];
- sprintf(msg,
+ snprintf(msg, sizeof(msg),
"(trouble) removeConnection(from->%d, to->%d), evaluating neighbour [%d] = node %d\n",
iFrom,
iTo,
@@ -669,19 +705,18 @@ bool cNodeMachine::removeConnection(int iFrom, int iTo) {
}
// Removes ALL neighbour connections on iNode
-bool cNodeMachine::remove_neighbour_nodes(int iNode) {
+bool cNodeMachine::remove_neighbour_nodes(const int iNode) {
if (iNode < 0)
return false;
- int i = 0;
- for (i = 0; i < MAX_NEIGHBOURS; i++)
- Nodes[iNode].iNeighbour[i] = -1;
+ for (int& i : Nodes[iNode].iNeighbour)
+ i = -1;
return true;
}
// returns the next free 'neighbour id' for that node
-int cNodeMachine::freeNeighbourNodeIndex(tNode *Node) {
+int cNodeMachine::freeNeighbourNodeIndex(const tNode *Node) {
for (int i = 0; i < MAX_NEIGHBOURS; i++) {
if (Node->iNeighbour[i] < 0) {
return i;
@@ -691,8 +726,20 @@ int cNodeMachine::freeNeighbourNodeIndex(tNode *Node) {
return -1;
}
+int cNodeMachine::is_neighbour_node(const tNode& node, const int iNode)
+{
+ for (int i = 0; i < MAX_NEIGHBOURS; i++) {
+ if (node.iNeighbour[i] == iNode) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
// Return the node id from bot path on Index NR
-int cNodeMachine::getNodeIndexFromBotForPath(int botIndex, int pathNodeIndex) {
+int cNodeMachine::getNodeIndexFromBotForPath(const int botIndex, const int pathNodeIndex) const
+{
if (botIndex > -1 && botIndex < MAX_BOTS &&
pathNodeIndex > -1 && pathNodeIndex < MAX_PATH_NODES) {
return iPath[botIndex][pathNodeIndex];
@@ -702,27 +749,25 @@ int cNodeMachine::getNodeIndexFromBotForPath(int botIndex, int pathNodeIndex) {
}
// Compute the horizontal distance between A and B (ignoring z coordinate)
-static float horizontal_distance(Vector a, Vector b) {
- return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
+static float horizontal_distance(const Vector& a, const Vector& b) {
+ return std::sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
-#define STEP 20 //Incremental move
+constexpr int STEP = 20; //Incremental move;
// Return the floor below V
// TO BE IMPROVED use pEntityCOntaining
-static Vector FloorBelow(Vector V) {
+static Vector FloorBelow(const Vector& V) {
static TraceResult tr; // Keep it available even outside of the call
- Vector ReallyDown, UpALittle;
- int HullNumber, HullHeight;
// First use this hull
- HullNumber = human_hull;
- HullHeight = 36;
+ int HullNumber = human_hull;
+ float HullHeight = 36.0f;
// Bump V a little higher (to allow for a steep climb)
- UpALittle = V + Vector(0, 0, HullHeight);
- ReallyDown = V + Vector(0, 0, -500);
- UTIL_TraceHull(UpALittle, ReallyDown, ignore_monsters, HullNumber, NULL, &tr);
+ Vector UpALittle = V + Vector(0, 0, HullHeight);
+ Vector ReallyDown = V + Vector(0, 0, -500);
+ UTIL_TraceHull(UpALittle, ReallyDown, ignore_monsters, HullNumber, nullptr, &tr);
//printf(" Floor %.0f -> %.0f, TraceHull fraction = %.2f, vecEndPos.z=%.0f %s %s\n",
//UpALittle.z,ReallyDown.z,tr.flFraction,tr.vecEndPos.z,
//(tr.fAllSolid) ? "AllSolid" : "",
@@ -730,7 +775,7 @@ static Vector FloorBelow(Vector V) {
if (tr.fStartSolid) { // Perhaps we where too high and hit the ceiling
UpALittle = V + Vector(0, 0, 0);
ReallyDown = V + Vector(0, 0, -500);
- UTIL_TraceHull(UpALittle, ReallyDown, ignore_monsters, HullNumber, NULL, &tr);
+ UTIL_TraceHull(UpALittle, ReallyDown, ignore_monsters, HullNumber, nullptr, &tr);
//printf(" Floor without raising %.0f -> %.0f, TraceHull fraction = %.2f, vecEndPos.z=%.0f %s %s\n",
//UpALittle.z,ReallyDown.z,tr.flFraction,tr.vecEndPos.z,
//(tr.fAllSolid) ? "AllSolid" : "",
@@ -740,7 +785,7 @@ static Vector FloorBelow(Vector V) {
HullHeight = 0;
UpALittle = V + Vector(0, 0, STEP);
ReallyDown = V + Vector(0, 0, -500);
- UTIL_TraceHull(UpALittle, ReallyDown, ignore_monsters, HullNumber, NULL, &tr);
+ UTIL_TraceHull(UpALittle, ReallyDown, ignore_monsters, HullNumber, nullptr, &tr);
//printf(" Floor with point hull %.0f -> %.0f, TraceHull fraction = %.2f, vecEndPos.z=%.0f %s %s\n",
//UpALittle.z,ReallyDown.z,tr.flFraction,tr.vecEndPos.z,
//(tr.fAllSolid) ? "AllSolid" : "",
@@ -763,13 +808,14 @@ static Vector FloorBelow(Vector V) {
// to a point in water or a point in the air
// - ducking and walking (assuming flat ground)
// - swimming
-int cNodeMachine::Reachable(const int iStart, const int iEnd) {
- Vector IncMove, Check, Floor, Start, End;
+int cNodeMachine::Reachable(const int iStart, const int iEnd) const
+{
+ Vector IncMove, Check, Floor;
float Dist, Height, PreviousHeight;
TraceResult tr;
- Start = Nodes[iStart].origin;
- End = Nodes[iEnd].origin;
+ const Vector Start = Nodes[iStart].origin;
+ const Vector End = Nodes[iEnd].origin;
#ifdef DEBUG_REACHABLE
printf("Reachable %d(%.0f,%.0f,%.0f)%s", iStart, Start.x, Start.y,
Start.z,
@@ -778,27 +824,27 @@ int cNodeMachine::Reachable(const int iStart, const int iEnd) {
(Nodes[iEnd].iNodeBits & BIT_LADDER) ? "OnLadder" : "");
#endif
// Just in case
- if (Start.x == 9999 || End.x == 9999)
- return false;
+ if (static_cast(Start.x) == 9999 || static_cast(End.x) == 9999)
+ return 0;
// Quick & dirty check whether we can go through...
// This is simply to quickly decide whether the move is impossible
- UTIL_TraceHull(Start, End, ignore_monsters, point_hull, NULL, &tr);
+ UTIL_TraceHull(Start, End, ignore_monsters, point_hull, nullptr, &tr);
#ifdef DEBUG_REACHABLE
printf("TraceHull --> tr.flFraction = %.2f\n", tr.flFraction);
#endif
- if (tr.flFraction < 1.0)
- return false;
+ if (tr.flFraction < 1.0f)
+ return 0;
// If either start/end is on ladder, assume we can fly without falling
// but still check whether a human hull can go through
- if ((Nodes[iStart].iNodeBits & BIT_LADDER) ||
- (Nodes[iEnd].iNodeBits & BIT_LADDER))
+ if (Nodes[iStart].iNodeBits & BIT_LADDER ||
+ Nodes[iEnd].iNodeBits & BIT_LADDER)
{
- UTIL_TraceHull(Start, End, ignore_monsters, human_hull, NULL, &tr);
- return tr.flFraction >= 1.0;
+ UTIL_TraceHull(Start, End, ignore_monsters, human_hull, nullptr, &tr);
+ return tr.flFraction >= 1.0f;
}
// Heurestic for falling
@@ -830,16 +876,16 @@ int cNodeMachine::Reachable(const int iStart, const int iEnd) {
#endif
if (Height > PreviousHeight) { // Going upwards
- if (Height - PreviousHeight > MAX_JUMPHEIGHT) {
+ if (Height - PreviousHeight > static_cast(MAX_JUMPHEIGHT)) {
//printf(" too high for upward jump\n") ;
- return false;
+ return 0;
}
} else { // Going downwards
- if (PreviousHeight - Height > MAX_FALLHEIGHT)
+ if (PreviousHeight - Height > static_cast(MAX_FALLHEIGHT))
if (UTIL_PointContents(Floor + Vector(0, 0, 5))
!= CONTENTS_WATER)
//{printf(" too high for a downward fall not in water\n") ;
- return false; // Falling from too high not in water
+ return 0; // Falling from too high not in water
//}
//else printf(" ouf we are in water\n") ;
}
@@ -856,15 +902,15 @@ int cNodeMachine::Reachable(const int iStart, const int iEnd) {
#endif
if (Height > PreviousHeight) { // Going upwards
- if (Height - PreviousHeight > MAX_JUMPHEIGHT) {
+ if (Height - PreviousHeight > static_cast(MAX_JUMPHEIGHT)) {
//printf(" too high for upward jump\n") ;
- return false;
+ return 0;
}
} else { // Going downwards
- if (PreviousHeight - Height > MAX_FALLHEIGHT)
+ if (PreviousHeight - Height > static_cast(MAX_FALLHEIGHT))
if (UTIL_PointContents(End) != CONTENTS_WATER) {
//printf(" too high for a downward fall not in water\n") ;
- return false; // Falling from too high not in water
+ return 0; // Falling from too high not in water
}
//else printf(" ouf we are in water\n") ;
}
@@ -877,24 +923,23 @@ int cNodeMachine::Reachable(const int iStart, const int iEnd) {
// TODO
// Success !
- return true;
+ return 1;
}
// Adding a node: another way...
-int cNodeMachine::add2(Vector vOrigin, int iType, edict_t *pEntity) {
+int cNodeMachine::add2(const Vector& vOrigin, const int iType, edict_t *pEntity) {
// Do not add a node when there is already one close
if (getClosestNode(vOrigin, NODE_ZONE, pEntity) > -1)
return -1;
- int newNodeIndex = getFreeNodeIndex();
+ const int newNodeIndex = getFreeNodeIndex();
if (newNodeIndex >= MAX_NODES || newNodeIndex < 0) {
return -1;
}
Nodes[newNodeIndex].origin = vOrigin;
- if (newNodeIndex > iMaxUsedNodes)
- iMaxUsedNodes = newNodeIndex;
+ iMaxUsedNodes = std::max(newNodeIndex, iMaxUsedNodes);
// Set different flags about the node
Nodes[newNodeIndex].iNodeBits = iType; // EVY's extension
@@ -944,7 +989,7 @@ int cNodeMachine::add2(Vector vOrigin, int iType, edict_t *pEntity) {
// When walking the human player can't pass a certain speed and distance
// however, when a human is falling, the distance will be bigger.
- int maxDistance = 3 * NODE_ZONE;
+ constexpr int maxDistance = 3 * NODE_ZONE;
if (horizontal_distance(Nodes[newNodeIndex].origin, Nodes[j].origin) > maxDistance)
continue;
@@ -966,28 +1011,28 @@ int cNodeMachine::add2(Vector vOrigin, int iType, edict_t *pEntity) {
}
/**
- * Returns a free node index, this is not bound to a meredian (subcluster)!
+ * Returns a free node index, this is not bound to a meridian (subcluster)!
* @return
*/
-int cNodeMachine::getFreeNodeIndex() {
- int i = 0;
- for (i = 0; i < MAX_NODES; i++) {
+int cNodeMachine::getFreeNodeIndex() const
+{
+ for (int i = 0; i < MAX_NODES; i++) {
if (Nodes[i].origin == INVALID_VECTOR) {
return i;
- break;
+ //break;
}
}
return -1; // no free node found
}
// Adding a node
-int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
+int cNodeMachine::addNode(const Vector& vOrigin, edict_t *pEntity) {
// Do not add a node when there is already one close
if (getClosestNode(vOrigin, NODE_ZONE, pEntity) > -1)
return -1;
- int currentIndex = getFreeNodeIndex();
+ const int currentIndex = getFreeNodeIndex();
// failed to find free node, bail
if (currentIndex < 0) {
@@ -998,8 +1043,8 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
// SET BITS:
bool bIsInWater = false;
- bool indexNodeFloats = false;
- bool bIndexOnCrate = false;
+ bool indexNodeFloats;
+ bool bIndexOnCrate;
if (pEntity) {
// Does this thing float?
@@ -1023,16 +1068,19 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
if (FUNC_IsOnLadder(pEntity))
indexNodeFloats = false;
- if (pEntity->v.button & IN_DUCK) {
+ if (pEntity->v.button & IN_DUCK)
// ??
Nodes[currentIndex].iNodeBits |= BIT_DUCK;
- }
+
+ //Experimental - This new node requires for bots to vault onto crates and edges? [APG]RoboCop[CL]
+ if (pEntity->v.button & BIT_DUCKJUMP)
+ Nodes[currentIndex].iNodeBits |= BIT_DUCKJUMP;
} // do only check pEntity when its not NULL
else {
// Does this thing float?
- indexNodeFloats = node_float(Nodes[currentIndex].origin, NULL);
- bIndexOnCrate = node_on_crate(Nodes[currentIndex].origin, NULL);
+ indexNodeFloats = node_float(Nodes[currentIndex].origin, nullptr);
+ bIndexOnCrate = node_on_crate(Nodes[currentIndex].origin, nullptr);
}
// add to subcluster
@@ -1065,8 +1113,8 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
// When walking the human player can't pass a certain speed and distance
// however, when a human is falling (or walking a slope), the distance will be bigger.
- float distanceBetweenVectorsWithoutZAxis = func_distance(vNormalizedOrigin, vNormalizedIndex);
- if (distanceBetweenVectorsWithoutZAxis > (NODE_ZONE * 3)) { // allow up to 3 times the boundary we use normally
+ const float distanceBetweenVectorsWithoutZAxis = func_distance(vNormalizedOrigin, vNormalizedIndex);
+ if (distanceBetweenVectorsWithoutZAxis > NODE_ZONE * 3) { // allow up to 3 times the boundary we use normally
continue;
}
@@ -1076,11 +1124,11 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
// Traceline from nodeIndex to index
bool bNeighbourFloats = node_float(Nodes[nodeIndex].origin, pEntity);
- bool bNeighOnCrate = node_on_crate(Nodes[nodeIndex].origin, pEntity);
+ const bool bNeighOnCrate = node_on_crate(Nodes[nodeIndex].origin, pEntity);
bool bNeighbourWater = false;
// when pEntity is on ladder, it is NOT floating!
- if (FUNC_IsOnLadder(pEntity))
+ if (pEntity && FUNC_IsOnLadder(pEntity))
bNeighbourFloats = false;
if (Nodes[nodeIndex].iNodeBits & BIT_LADDER)
@@ -1092,25 +1140,24 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
// Check if Index is LOWER then J, if so, the height should be jumpable!
// When height does not differ to much we can add this connection.
//
- //
// 14/06/04 - fix: Some slopes are not counted in here..., de_dust jump from crates connects now
- bool nodeIsHigherThanOrigin = Nodes[nodeIndex].origin.z > Nodes[currentIndex].origin.z;
+ const bool nodeIsHigherThanOrigin = Nodes[nodeIndex].origin.z > Nodes[currentIndex].origin.z;
// this assumes 'our' position is lower, this determines 'slope' distance
- vec_t slopeDistance = Nodes[nodeIndex].origin.z - Nodes[currentIndex].origin.z;
+ const vec_t slopeDistance = Nodes[nodeIndex].origin.z - Nodes[currentIndex].origin.z;
// this assumes 'our' position is higher, so we can determine fall distance
- vec_t fallDistance = Nodes[currentIndex].origin.z - Nodes[nodeIndex].origin.z;
+ const vec_t fallDistance = Nodes[currentIndex].origin.z - Nodes[nodeIndex].origin.z;
if (indexNodeFloats
- && (fallDistance > MAX_FALLHEIGHT)
+ && fallDistance > static_cast(MAX_FALLHEIGHT)
&& (!bNeighbourWater && !bIsInWater)) {
// skip nodes that are not in water and too low (ie will cause fall damage)
continue;
}
// skip nodes which are to high (fall damage)
- if (fallDistance > MAX_FALLHEIGHT) {
+ if (fallDistance > static_cast(MAX_FALLHEIGHT)) {
continue;
}
@@ -1121,7 +1168,7 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
if (indexNodeFloats == false && // we stand on something
nodeIsHigherThanOrigin && // we MUST jump (not fall)
bNeighbourWater == false &&
- fabs(slopeDistance) > MAX_JUMPHEIGHT) // and cannot jump to it
+ std::fabs(slopeDistance) > static_cast(MAX_JUMPHEIGHT)) // and cannot jump to it
{
// SERVER_PRINT("Cannot jump to it");
continue; // next neighbour
@@ -1131,7 +1178,7 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
if (indexNodeFloats == false && // we stand on something
nodeIsHigherThanOrigin && // we MUST jump (not fall)
bNeighbourWater == false &&
- fabs(slopeDistance) > MAX_FALLHEIGHT) // and cannot jump to it
+ std::fabs(slopeDistance) > static_cast(MAX_FALLHEIGHT)) // and cannot jump to it
{
// SERVER_PRINT("Insanity jump not possible either!\n");
continue; // next neighbour
@@ -1140,13 +1187,13 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
int hull_type = head_hull;
- if (FUNC_IsOnLadder(pEntity)) {
+ if (pEntity && FUNC_IsOnLadder(pEntity)) {
hull_type = point_hull;
} else {
// falling
// 14/06/05 - this code does not cause bad connections! - Stefan
// 20/06/05 - oops, it does... because it blocks when we are NOT falling...
- if (slopeDistance > MAX_FALLHEIGHT) {
+ if (slopeDistance > static_cast(MAX_FALLHEIGHT)) {
hull_type = human_hull; // when we fall, be sure we can freely fall.
}
@@ -1164,10 +1211,10 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
// trace
UTIL_TraceHull(Nodes[currentIndex].origin, Nodes[nodeIndex].origin, ignore_monsters,
- hull_type, pEntity->v.pContainingEntity, &tr);
+ hull_type, pEntity ? pEntity->v.pContainingEntity : nullptr, &tr);
// if nothing hit:
- if (tr.flFraction >= 1.0) {
+ if (tr.flFraction >= 1.0f) {
// Add this to the neighbouring list
Nodes[currentIndex].iNeighbour[neighbourId] = nodeIndex;
@@ -1179,11 +1226,11 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
// Check if J is LOWER then Index, if so, the height should be jumpable!
// When height does not differ to much we can add this connection.
- if ((indexNodeFloats && bNeighbourFloats)
+ if (indexNodeFloats && bNeighbourFloats
&& (bNeighbourWater == false && bIsInWater == false)
&& Nodes[currentIndex].origin.z >= Nodes[nodeIndex].origin.z) {
char msg[80];
- sprintf(msg, "J.Z = %f, INDEX.Z = %f\n", Nodes[nodeIndex].origin.z,
+ snprintf(msg, sizeof(msg), "J.Z = %f, INDEX.Z = %f\n", Nodes[nodeIndex].origin.z,
Nodes[currentIndex].origin.z);
// UTIL_ClientPrintAll( HUD_PRINTNOTIFY, msg);
bCanConnect = false; // cannot connect
@@ -1193,7 +1240,7 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
if (bNeighbourFloats == false && // we stand on something
Nodes[currentIndex].origin.z > Nodes[nodeIndex].origin.z && // we MUST jump (not fall)
bIsInWater == false &&
- fabs(fallDistance) > MAX_JUMPHEIGHT) // and cannot jump to it
+ std::fabs(fallDistance) > static_cast(MAX_JUMPHEIGHT)) // and cannot jump to it
bCanConnect = false; // cannot connect
// All water stuff can connect to each other
@@ -1201,7 +1248,7 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
bCanConnect = true;
if (bCanConnect) {
- int jNeigh = freeNeighbourNodeIndex(&Nodes[nodeIndex]);
+ const int jNeigh = freeNeighbourNodeIndex(&Nodes[nodeIndex]);
if (jNeigh > -1)
Nodes[nodeIndex].iNeighbour[jNeigh] = currentIndex; // reversed also possible
}
@@ -1218,8 +1265,7 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
}
- if (currentIndex > iMaxUsedNodes)
- iMaxUsedNodes = currentIndex;
+ iMaxUsedNodes = std::max(currentIndex, iMaxUsedNodes);
//UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "NodeMachine: Succesfully added node\n");
return currentIndex;
@@ -1227,9 +1273,10 @@ int cNodeMachine::addNode(Vector vOrigin, edict_t *pEntity) {
// Players initialization
void cNodeMachine::init_players() {
- for (int i = 0; i < 32; i++) {
- Players[i].vPrevPos = Vector(9999, 9999, 9999);
- Players[i].iNode = -1;
+ for (tPlayer& Player : Players)
+ {
+ Player.vPrevPos = Vector(9999, 9999, 9999);
+ Player.iNode = -1;
}
}
@@ -1237,10 +1284,10 @@ void cNodeMachine::init_players() {
void cNodeMachine::init_round() {
//UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "NodeMachine: Roundstart\n");
for (int index = 1; index <= gpGlobals->maxClients; index++) {
- edict_t *pPlayer = INDEXENT(index);
+ const edict_t *pPlayer = INDEXENT(index);
// skip invalid players
- if ((pPlayer) && (!pPlayer->free))
+ if (pPlayer && !pPlayer->free)
Players[(index - 1)].vPrevPos = pPlayer->v.origin;
}
@@ -1249,9 +1296,9 @@ void cNodeMachine::init_round() {
path_clear(p);
// decrease bad score for bad goal nodes
- for (int g = 0; g < MAX_GOALS; g++)
- if (Goals[g].iBadScore > 0)
- Goals[g].iBadScore--;
+ for (tGoal& Goal : Goals)
+ if (Goal.iBadScore > 0)
+ Goal.iBadScore--;
}
/**
@@ -1259,17 +1306,16 @@ void cNodeMachine::init_round() {
*/
void cNodeMachine::addNodesForPlayers() {
for (int index = 1; index <= gpGlobals->maxClients; index++) {
- edict_t *pPlayer = INDEXENT(index);
+ edict_t* pPlayer = INDEXENT(index);
// skip invalid (dead, not playing) players
- if ((pPlayer) && (!pPlayer->free)) {
- if (pPlayer->free) continue;
+ if (pPlayer && !pPlayer->free) {
if (!IsAlive(pPlayer)) continue;
- int iPlayerIndex = index - 1;
+ const int iPlayerIndex = index - 1;
// within a certain distance no node found? add one
- if (func_distance(pPlayer->v.origin, Players[iPlayerIndex].vPrevPos) > NODE_ZONE) {
+ if (func_distance(pPlayer->v.origin, Players[iPlayerIndex].vPrevPos) > static_cast(NODE_ZONE)) {
Players[iPlayerIndex].vPrevPos = pPlayer->v.origin;
add2(pPlayer->v.origin, 0, pPlayer);
}
@@ -1278,57 +1324,56 @@ void cNodeMachine::addNodesForPlayers() {
}
// Draw connections of the node we are standing on
-void cNodeMachine::connections(edict_t *pEntity) {
-
- int closeNode = -1;
- char msg[75];
- memset(msg, 0, sizeof(msg));
+void cNodeMachine::connections(edict_t *pEntity) const
+{
+ int closeNode;
+ char msg[75] = {};
if (draw_nodepath > -1 && draw_nodepath < 32) {
cBot botPointer = bots[draw_nodepath];
if (botPointer.bIsUsed) {
closeNode = botPointer.determineCurrentNodeWithTwoAttempts();
if (closeNode > -1) {
- Vector &vector = Nodes[closeNode].origin;
- sprintf(msg, "Bot [%s|%d] is at node %d (%f,%f,%f)\n", botPointer.name, draw_nodepath, closeNode, vector.x, vector.y, vector.z);
+ const Vector &vector = Nodes[closeNode].origin;
+ snprintf(msg, sizeof(msg), "Bot [%s|%d] is at node %d (%f,%f,%f)\n", botPointer.name, draw_nodepath, closeNode, vector.x, vector.y, vector.z);
} else {
- sprintf(msg, "Bot [%s|%d] is at node %d\n", botPointer.name, draw_nodepath, closeNode);
+ snprintf(msg, sizeof(msg), "Bot [%s|%d] is at node %d\n", botPointer.name, draw_nodepath, closeNode);
}
} else {
closeNode = getClosestNode(pEntity->v.origin, NODE_ZONE, pEntity);
if (closeNode > -1) {
- Vector &vector = Nodes[closeNode].origin;
- sprintf(msg, "No bot used for slot [%d], YOU are at node %d (%f,%f,%f)\n", draw_nodepath, closeNode, vector.x, vector.y, vector.z);
+ const Vector &vector = Nodes[closeNode].origin;
+ snprintf(msg, sizeof(msg), "No bot used for slot [%d], YOU are at node %d (%f,%f,%f)\n", draw_nodepath, closeNode, vector.x, vector.y, vector.z);
} else {
- sprintf(msg, "No bot used for slot [%d], YOU are at node %d\n", draw_nodepath, closeNode);
+ snprintf(msg, sizeof(msg), "No bot used for slot [%d], YOU are at node %d\n", draw_nodepath, closeNode);
}
}
} else {
closeNode = getClosestNode(pEntity->v.origin, NODE_ZONE, pEntity);
- sprintf(msg, "YOU are at node %d\n", closeNode);
+ snprintf(msg, sizeof(msg), "YOU are at node %d\n", closeNode);
}
CenterMessage(msg);
if (closeNode > -1) {
for (int j = 0; j < MAX_NEIGHBOURS; j++) {
- tNode &node = Nodes[closeNode];
- int neighbourNode = node.iNeighbour[j];
+ const tNode &node = Nodes[closeNode];
+ const int neighbourNode = node.iNeighbour[j];
if (neighbourNode > -1) {
- Vector start = node.origin;
- Vector end = Nodes[neighbourNode].origin;
+ const Vector start = node.origin;
+ const Vector end = Nodes[neighbourNode].origin;
int red = 0;
int green = 255;
int blue = 0;
- int troubleIndex = GetTroubleIndexForConnection(closeNode, neighbourNode);
+ const int troubleIndex = GetTroubleIndexForConnection(closeNode, neighbourNode);
if (troubleIndex > -1) {
- int tries = Troubles[troubleIndex].iTries;
+ const int tries = Troubles[troubleIndex].iTries;
if (tries <= 1) {
red = 255;
- green = 255;
+ green = 250;
blue = 0;
}
@@ -1339,7 +1384,7 @@ void cNodeMachine::connections(edict_t *pEntity) {
}
if (tries > 2) {
- red = 128;
+ red = 150;
green = 0;
blue = 0;
}
@@ -1355,37 +1400,48 @@ void cNodeMachine::connections(edict_t *pEntity) {
}
// Draw
-void cNodeMachine::draw(edict_t *pEntity) {
- //DebugOut("waypoint: waypoint_draw()\n");
- int i = 0, max_drawn = 0;
+void cNodeMachine::draw(edict_t* pEntity) const
+{
+ // DebugOut("waypoint: waypoint_draw()\n");
+ int max_drawn = 0;
+
+ // Declare 'start' vector outside the loop
+ Vector start;
- for (i = 0; i < MAX_NODES; i++) {
- if (Nodes[i].origin != Vector(9999, 9999, 9999)) {
- Vector start = Nodes[i].origin - Vector(0, 0, 36);
- Vector end = Nodes[i].origin;
+ for (const tNode& Node : Nodes)
+ {
+ if (Node.origin != Vector(9999, 9999, 9999)) {
+ start = Node.origin - Vector(0, 0, 36);
+ Vector end = Node.origin;
- bool good = VectorIsVisibleWithEdict(pEntity, end, "none");
+ const bool good = VectorIsVisibleWithEdict(pEntity, end, "none");
- int angle_to_waypoint =
- FUNC_InFieldOfView(pEntity, (end - pEntity->v.origin));
+ const int angle_to_waypoint =
+ FUNC_InFieldOfView(pEntity, end - pEntity->v.origin);
if (good && angle_to_waypoint < 65) {
- int r, g, b, l;
- r = g = b = l = 250;
- l = 250;
- //l = 250; // Normally light is 250
+ int g, b, l;
+ int r = g = b = l = 250;
- if (Nodes[i].iNodeBits & BIT_LADDER)
+ // l = 250; // Normally light is 250
+
+ if (Node.iNodeBits & BIT_LADDER)
b = g = 0;
- if (Nodes[i].iNodeBits & BIT_WATER)
+ if (Node.iNodeBits & BIT_WATER)
r = g = 0;
- if (Nodes[i].iNodeBits & BIT_DUCK)
- r = b = 0;
+ if (Node.iNodeBits & BIT_DUCK)
+ r = b = 50;
+ // Jump and DuckJump were missing for those nodes? [APG]RoboCop[CL]
+ if (Node.iNodeBits & BIT_JUMP)
+ r = b = 100;
+
+ if (Node.iNodeBits & BIT_DUCKJUMP)
+ r = b = 150;
- if (Nodes[i].iNeighbour[0] < 0)
+ if (Node.iNeighbour[0] < 0)
r = 0;
if (max_drawn < 39) {
@@ -1393,32 +1449,43 @@ void cNodeMachine::draw(edict_t *pEntity) {
max_drawn++;
}
}
- } // for
+ } // for
+ }
+
+ const int iNodeClose = getClosestNode(pEntity->v.origin, NODE_ZONE, pEntity);
+ if (iNodeClose >= static_cast(std::size(Nodes))) {
+ char msg[50];
+ snprintf(msg, sizeof(msg), "Node %d\nMe: (%.0f,%.0f,%.0f)\n", iNodeClose,
+ pEntity->v.origin.x, pEntity->v.origin.y,
+ pEntity->v.origin.z);
+ CenterMessage(msg);
+ return;
}
- int iNodeClose = getClosestNode(pEntity->v.origin, NODE_ZONE, pEntity);
char msg[50];
char Flags[10];
Flags[0] = 0;
- if (Nodes[iNodeClose].iNodeBits & BIT_LADDER)
- strcat(Flags, "L");
-
- if (Nodes[iNodeClose].iNodeBits & BIT_WATER)
- strcat(Flags, "W");
-
- if (Nodes[iNodeClose].iNodeBits & BIT_JUMP)
- strcat(Flags, "J");
-
- if (Nodes[iNodeClose].iNodeBits & BIT_DUCK)
- strcat(Flags, "D");
-
- sprintf(msg, "Node %d(%.0f,%.0f,%.0f)%s\nMe: (%.0f,%.0f,%.0f)\n",
- iNodeClose, (iNodeClose < 0) ? -1 : Nodes[iNodeClose].origin.x,
- (iNodeClose < 0) ? -1 : Nodes[iNodeClose].origin.y,
- (iNodeClose < 0) ? -1 : Nodes[iNodeClose].origin.z, Flags,
- pEntity->v.origin.x, pEntity->v.origin.y, pEntity->v.origin.z);
+ if (iNodeClose >= 0)
+ {
+ if (Nodes[iNodeClose].iNodeBits & BIT_LADDER)
+ std::strcat(Flags, "L");
+ if (Nodes[iNodeClose].iNodeBits & BIT_WATER)
+ std::strcat(Flags, "W");
+ if (Nodes[iNodeClose].iNodeBits & BIT_JUMP)
+ std::strcat(Flags, "J");
+ if (Nodes[iNodeClose].iNodeBits & BIT_DUCK)
+ std::strcat(Flags, "D");
+ // Experimental DuckJump added for this new node [APG]RoboCop[CL]
+ if (Nodes[iNodeClose].iNodeBits & BIT_DUCKJUMP)
+ std::strcat(Flags, "h");
+ }
+ snprintf(msg, sizeof(msg), "Node %d(%.0f,%.0f,%.0f)%s\nMe: (%.0f,%.0f,%.0f)\n",
+ iNodeClose, iNodeClose < 0 ? -1 : Nodes[iNodeClose].origin.x,
+ iNodeClose < 0 ? -1 : Nodes[iNodeClose].origin.y,
+ iNodeClose < 0 ? -1 : Nodes[iNodeClose].origin.z, Flags,
+ pEntity->v.origin.x, pEntity->v.origin.y, pEntity->v.origin.z);
CenterMessage(msg);
}
@@ -1426,39 +1493,34 @@ void cNodeMachine::draw(edict_t *pEntity) {
void cNodeMachine::experience_save() {
char dirname[256];
char filename[256];
- int i;
// Set Directory name
- strcpy(dirname, "data/cstrike/exp/");
- strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, ".rbx"); // nodes file
+ std::strcpy(dirname, "data/cstrike/exp/");
+ std::strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, ".rbx"); // nodes file
// writes whole path into "filename", Linux compatible
UTIL_BuildFileNameRB(dirname, filename);
- FILE *rbl;
// Only save if lock type is < 1
- rbl = fopen(filename, "wb");
+ FILE* rbl = std::fopen(filename, "wb");
- if (rbl != NULL) {
- int iVersion = FILE_EXP_VER2;
- fwrite(&iVersion, sizeof(int), 1, rbl);
+ if (rbl != nullptr) {
+ constexpr int iVersion = FILE_EXP_VER2;
+ std::fwrite(&iVersion, sizeof(int), 1, rbl);
- for (i = 0; i < MAX_NODES; i++) {
- fwrite(&InfoNodes[i].fDanger[0], sizeof(Vector), 1, rbl);
- fwrite(&InfoNodes[i].fDanger[1], sizeof(Vector), 1, rbl);
-
- fwrite(&InfoNodes[i].fContact[0], sizeof(Vector), 1, rbl);
- fwrite(&InfoNodes[i].fContact[1], sizeof(Vector), 1, rbl);
+ // Write the InfoNodes data directly using the correct struct
+ for (tInfoNode& InfoNode : InfoNodes)
+ {
+ std::fwrite(&InfoNode, sizeof(tInfoNode), 1, rbl);
}
- if (iMaxUsedNodes > MAX_NODES)
- iMaxUsedNodes = MAX_NODES;
+ iMaxUsedNodes = std::min(iMaxUsedNodes, MAX_NODES);
// Here write down the MAX amounts of nodes used from vis table!
- unsigned long iSize = (iMaxUsedNodes * MAX_NODES) / 8;
+ const unsigned long iSize = iMaxUsedNodes * MAX_NODES / 8;
- fwrite(&iMaxUsedNodes, sizeof(int), 1, rbl);
+ std::fwrite(&iMaxUsedNodes, sizeof(int), 1, rbl);
// Write down 512 bytes chunks, and when a remaining piece is left over
// also write that down. Only when 'size' is 0 we quit the loop
@@ -1473,7 +1535,7 @@ void cNodeMachine::experience_save() {
// While we still have bytes remaining to write to disk.
while (iRemaining > 0) {
- fwrite(&cVisTable[iPos], iChunk, 1, rbl);
+ std::fwrite(&cVisTable[iPos], iChunk, 1, rbl);
iChunk = 512; // keep the size 512
@@ -1489,69 +1551,58 @@ void cNodeMachine::experience_save() {
}
// write down the checked vis
- fwrite(iVisChecked, sizeof(iVisChecked), 1, rbl);
- fclose(rbl);
+ std::fwrite(iVisChecked, sizeof(iVisChecked), 1, rbl);
+ std::fclose(rbl);
} else
- fprintf(stderr, "Cannot write experience file %s\n", filename);
+ std::fprintf(stderr, "Cannot write experience file %s\n", filename);
}
// Load Danger
void cNodeMachine::experience_load() {
char dirname[256];
char filename[256];
- int i;
// Set Directory name
- strcpy(dirname, "data/cstrike/exp/");
- strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, ".rbx"); // nodes file
+ std::strcpy(dirname, "data/cstrike/exp/");
+ std::strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, ".rbx"); // nodes file
// writes whole path into "filename", Linux compatible
UTIL_BuildFileNameRB(dirname, filename);
- FILE *rbl;
- rbl = fopen(filename, "rb");
+ FILE* rbl = std::fopen(filename, "rb");
- if (rbl != NULL) {
+ if (rbl != nullptr) {
+ int i;
int iVersion = FILE_EXP_VER1;
- fread(&iVersion, sizeof(int), 1, rbl);
+ std::fread(&iVersion, sizeof(int), 1, rbl);
if (iVersion == FILE_EXP_VER1) {
for (i = 0; i < MAX_NODES; i++) {
- fread(&InfoNodes[i].fDanger[0], sizeof(Vector), 1, rbl);
- fread(&InfoNodes[i].fDanger[1], sizeof(Vector), 1, rbl);
-
- fread(&InfoNodes[i].fContact[0], sizeof(Vector), 1, rbl);
- fread(&InfoNodes[i].fContact[1], sizeof(Vector), 1, rbl);
+ std::fread(&InfoNodes[i], sizeof(tInfoNode), 1, rbl);
}
- fread(&iMaxUsedNodes, sizeof(int), 1, rbl);
+ std::fread(&iMaxUsedNodes, sizeof(int), 1, rbl);
// make sure we never exceed the limit
- if (iMaxUsedNodes > MAX_NODES)
- iMaxUsedNodes = MAX_NODES;
+ iMaxUsedNodes = std::min(iMaxUsedNodes, MAX_NODES);
- unsigned long iSize = (iMaxUsedNodes * MAX_NODES) / 8;
+ const unsigned long iSize = iMaxUsedNodes * MAX_NODES / 8;
// Read table from what we know
- fread(cVisTable, iSize, 1, rbl);
- fread(iVisChecked, sizeof(iVisChecked), 1, rbl);
- } else if (iVersion == FILE_EXP_VER2) {
+ std::fread(cVisTable.data(), iSize, 1, rbl);
+ std::fread(iVisChecked, sizeof(iVisChecked), 1, rbl);
+ }
+ else if (iVersion == FILE_EXP_VER2) {
for (i = 0; i < MAX_NODES; i++) {
- fread(&InfoNodes[i].fDanger[0], sizeof(Vector), 1, rbl);
- fread(&InfoNodes[i].fDanger[1], sizeof(Vector), 1, rbl);
-
- fread(&InfoNodes[i].fContact[0], sizeof(Vector), 1, rbl);
- fread(&InfoNodes[i].fContact[1], sizeof(Vector), 1, rbl);
+ std::fread(&InfoNodes[i], sizeof(tInfoNode), 1, rbl);
}
- fread(&iMaxUsedNodes, sizeof(int), 1, rbl);
-
+ std::fread(&iMaxUsedNodes, sizeof(int), 1, rbl);
// make sure we never exceed the limit
- if (iMaxUsedNodes > MAX_NODES)
- iMaxUsedNodes = MAX_NODES;
+ iMaxUsedNodes = std::min(iMaxUsedNodes, MAX_NODES);
- unsigned long iSize = (iMaxUsedNodes * MAX_NODES) / 8;
+ const unsigned long iSize = iMaxUsedNodes * MAX_NODES / 8;
// Now read the cVisTable from what we know
ClearVisibilityTable(); // clear first
@@ -1566,7 +1617,7 @@ void cNodeMachine::experience_load() {
break;
// Read table from what we know
- fread(&cVisTable[iPos], iChunk, 1, rbl);
+ std::fread(&cVisTable[iPos], iChunk, 1, rbl);
// When we exceed the size we make sure that the chunk is not to big
if (iRemaining < iChunk)
@@ -1579,82 +1630,84 @@ void cNodeMachine::experience_load() {
break; // escape
}
- fread(iVisChecked, sizeof(iVisChecked), 1, rbl);
+ std::fread(iVisChecked, sizeof(iVisChecked), 1, rbl);
}
- fclose(rbl);
+ std::fclose(rbl);
}
}
// Save
-void cNodeMachine::save() {
+void cNodeMachine::save() const
+{
char dirname[256];
char filename[256];
- int i, n;
// Set Directory name
- strcpy(dirname, "data/cstrike/maps/");
- strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, ".rbn"); // nodes file
+ std::strcpy(dirname, "data/cstrike/maps/");
+ std::strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, ".rbn"); // nodes file
// writes whole path into "filename", Linux compatible
UTIL_BuildFileNameRB(dirname, filename);
- FILE *rbl;
// Only save if lock type is < 1
- rbl = fopen(filename, "wb");
+ FILE* rbl = std::fopen(filename, "wb");
- if (rbl != NULL) {
+ if (rbl != nullptr) {
// Write down version number
- int iVersion = FILE_NODE_VER1;
- fwrite(&iVersion, sizeof(int), 1, rbl);
- for (i = 0; i < MAX_NODES; i++) {
- fwrite(&Nodes[i].origin, sizeof(Vector), 1, rbl);
- for (n = 0; n < MAX_NEIGHBOURS; n++)
- fwrite(&Nodes[i].iNeighbour[n], sizeof(int), 1, rbl);
+ constexpr int iVersion = FILE_NODE_VER1;
+ std::fwrite(&iVersion, sizeof(int), 1, rbl);
+ for (const tNode& Node : Nodes)
+ {
+ std::fwrite(&Node.origin, sizeof(Vector), 1, rbl);
+ for (const int& n : Node.iNeighbour)
+ std::fwrite(&n, sizeof(int), 1, rbl);
// save bit flags
- fwrite(&Nodes[i].iNodeBits, sizeof(int), 1, rbl);
+ std::fwrite(&Node.iNodeBits, sizeof(int), 1, rbl);
}
- fclose(rbl);
+ std::fclose(rbl);
} else
- fprintf(stderr, "Cannot write file %s\n", filename);
+ std::fprintf(stderr, "Cannot write file %s\n", filename);
}
-void cNodeMachine::save_important() {
+void cNodeMachine::save_important() const
+{
char dirname[256];
char filename[256];
// Set Directory name
- strcpy(dirname, "data/cstrike/ini/");
- strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, ".ini"); // nodes file
+ std::strcpy(dirname, "data/cstrike/ini/");
+ std::strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, ".ini"); // nodes file
// writes whole path into "filename", Linux compatible
UTIL_BuildFileNameRB(dirname, filename);
// Only save if lock type is < 1
- FILE *rbl = fopen(filename, "w+t");
+ FILE *rbl = std::fopen(filename, "w+t");
if (rbl) {
- fprintf(rbl,
+ std::fprintf(rbl,
"; RealBot : Important Area Definition file\n; Do not hand-edit, this is _not_ an editable ini file!\n;\n\n");
// save important areas:
- for (int iGn = 0; iGn < MAX_GOALS; iGn++) {
- if (Goals[iGn].iType == GOAL_IMPORTANT) {
+ for (const tGoal& Goal : Goals)
+ {
+ if (Goal.iType == GOAL_IMPORTANT) {
// save this area
- fprintf(rbl, "[AREA]\n");
- Vector iGoalVector = node_vector(Goals[iGn].iNode);
- fprintf(rbl, "X=%f\n", iGoalVector.x);
- fprintf(rbl, "Y=%f\n", iGoalVector.y);
- fprintf(rbl, "Z=%f\n\n", iGoalVector.z);
+ std::fprintf(rbl, "[AREA]\n");
+ const Vector iGoalVector = node_vector(Goal.iNode);
+ std::fprintf(rbl, "X=%f\n", iGoalVector.x);
+ std::fprintf(rbl, "Y=%f\n", iGoalVector.y);
+ std::fprintf(rbl, "Z=%f\n\n", iGoalVector.z);
}
}
- fprintf(rbl, "; Eof");
- fclose(rbl);
+ std::fprintf(rbl, "; Eof");
+ std::fclose(rbl);
}
}
@@ -1662,34 +1715,34 @@ void cNodeMachine::save_important() {
void cNodeMachine::load() {
char dirname[256];
char filename[256];
- int i, n;
// Set Directory name
- strcpy(dirname, "data/cstrike/maps/");
+ std::strcpy(dirname, "data/cstrike/maps/");
- strcat(dirname, STRING(gpGlobals->mapname));
- strcat(dirname, ".rbn"); // nodes file
+ std::strcat(dirname, STRING(gpGlobals->mapname));
+ std::strcat(dirname, ".rbn"); // nodes file
// writes whole path into "filename", Linux compatible
UTIL_BuildFileNameRB(dirname, filename);
- FILE *rbl;
- rbl = fopen(filename, "rb");
+ FILE* rbl = std::fopen(filename, "rb");
- if (rbl != NULL) {
- int iVersion = FILE_NODE_VER1;
- fread(&iVersion, sizeof(int), 1, rbl);
+ if (rbl != nullptr) {
+ int i;
+ int iVersion = FILE_NODE_VER1;
+ std::fread(&iVersion, sizeof(int), 1, rbl);
// Version 1.0
if (iVersion == FILE_NODE_VER1) {
for (i = 0; i < MAX_NODES; i++) {
- fread(&Nodes[i].origin, sizeof(Vector), 1, rbl);
- for (n = 0; n < MAX_NEIGHBOURS; n++) {
- fread(&Nodes[i].iNeighbour[n], sizeof(int), 1, rbl);
+ std::fread(&Nodes[i].origin, sizeof(Vector), 1, rbl);
+ for (int& n : Nodes[i].iNeighbour)
+ {
+ std::fread(&n, sizeof(int), 1, rbl);
}
// save bit flags
- fread(&Nodes[i].iNodeBits, sizeof(int), 1, rbl);
+ std::fread(&Nodes[i].iNodeBits, sizeof(int), 1, rbl);
if (Nodes[i].origin != Vector(9999, 9999, 9999))
iMaxUsedNodes = i;
@@ -1704,7 +1757,7 @@ void cNodeMachine::load() {
AddToMeredian(iX, iY, i);
}
- fclose(rbl);
+ std::fclose(rbl);
// 04/07/04
// Check for full nodes table
@@ -1713,7 +1766,7 @@ void cNodeMachine::load() {
rblog("!!! Nodes table is full\n");
char msg[80];
- sprintf(msg, "After NodeMachine::load iMaxUsedNodes=%d\n",
+ snprintf(msg, sizeof(msg), "After NodeMachine::load iMaxUsedNodes=%d\n",
iMaxUsedNodes);
rblog(msg);
SERVER_PRINT("Going to load IAD file : ");
@@ -1726,35 +1779,44 @@ void cNodeMachine::load() {
}
void cNodeMachine::ClearImportantGoals() {
- for (int iGn = 0; iGn < MAX_GOALS; iGn++) {
- if (Goals[iGn].iType == GOAL_IMPORTANT && Goals[iGn].iNode > -1) {
- Goals[iGn].iType = -1;
- Goals[iGn].iNode = -1;
- Goals[iGn].pGoalEdict = NULL;
- memset(Goals[iGn].name, 0, sizeof(Goals[iGn].name));
+ for (tGoal& Goal : Goals)
+ {
+ if (Goal.iType == GOAL_IMPORTANT && Goal.iNode > -1) {
+ Goal.iType = -1;
+ Goal.iNode = -1;
+ Goal.pGoalEdict = nullptr;
+ std::memset(Goal.name, 0, sizeof(Goal.name));
}
}
}
// Draw path 0 (user)
-void cNodeMachine::path_draw(edict_t *pEntity) {
+void cNodeMachine::path_draw(edict_t* pEntity) const
+{
//DebugOut("waypoint: waypoint_draw()\n");
- int i = 0, max_drawn = 0;
-
- for (i = 0; i < MAX_NODES; i++) {
- int iNode = iPath[draw_nodepath][i];
- int iNextNode = iPath[draw_nodepath][(i + 1)];
+ int max_drawn = 0;
+
+ // Declare 'start' vector outside the loop
+ Vector start;
+ for (int i = 0; i < MAX_NODES; i++) {
+ const int iNode = iPath[draw_nodepath][i];
+ int iNextNode = -1; // Initialize to -1
+
+ if (i < MAX_NODES - 1) { // Check if i is less than MAX_NODES - 1
+ iNextNode = iPath[draw_nodepath][(i + 1)];
+ }
+
if (iNode > -1 && iNextNode > -1) {
- Vector start = Nodes[iNode].origin;
+ start = Nodes[iNode].origin;
Vector end = Nodes[iNextNode].origin;
- bool good = VectorIsVisibleWithEdict(pEntity, end, "none");
- int angle_to_waypoint =
- FUNC_InFieldOfView(pEntity, (end - pEntity->v.origin));
+ const bool good = VectorIsVisibleWithEdict(pEntity, end, "none");
+ const int angle_to_waypoint =
+ FUNC_InFieldOfView(pEntity, end - pEntity->v.origin);
if (max_drawn < 39 && good && angle_to_waypoint < 50) {
- int red = 255;
+ constexpr int red = 255;
int green = 0;
int blue = 255;
int width = 15;
@@ -1783,7 +1845,7 @@ void cNodeMachine::path_draw(edict_t *pEntity) {
}
// Spread contact areas
-void cNodeMachine::contact(int iNode, int iTeam) {
+void cNodeMachine::contact(const int iNode, const int iTeam) {
if (iNode < 0 || iNode >= MAX_NODES)
return;
@@ -1801,19 +1863,19 @@ void cNodeMachine::contact(int iNode, int iTeam) {
// Go through all valid nodes, except iNode, and increase danger if needed.
for (int i = 0; i < MAX_NODES; i++) {
if (Nodes[i].origin != Vector(9999, 9999, 9999) && i != iNode) {
- float fDist = func_distance(Nodes[i].origin, Nodes[iNode].origin);
- if (fDist < NODE_CONTACT_DIST) {
+ const float fDist = func_distance(Nodes[i].origin, Nodes[iNode].origin);
+ if (fDist < static_cast(NODE_CONTACT_DIST)) {
//Using TraceHull to detect de_aztec bridge and other entities.
TraceResult tr;
//UTIL_TraceHull(Nodes[iNode].origin, Nodes[i].origin, ignore_monsters, human_hull, NULL, &tr);
UTIL_TraceHull(Nodes[iNode].origin, Nodes[i].origin,
- ignore_monsters, point_hull, NULL, &tr);
+ ignore_monsters, point_hull, nullptr, &tr);
// within distance and 'reachable'
- if (tr.flFraction >= 1.0) {
- double costIncrease = (fDist / NODE_CONTACT_DIST) * NODE_CONTACT_STEP;
- InfoNodes[i].fContact[iTeam] += costIncrease;
+ if (tr.flFraction >= 1.0f) {
+ const double costIncrease = fDist / static_cast(NODE_CONTACT_DIST) * NODE_CONTACT_STEP;
+ InfoNodes[i].fContact[iTeam] += static_cast(costIncrease);
}
}
}
@@ -1821,7 +1883,7 @@ void cNodeMachine::contact(int iNode, int iTeam) {
}
// Spread danger around
-void cNodeMachine::danger(int iNode, int iTeam) {
+void cNodeMachine::danger(const int iNode, const int iTeam) {
if (iNode < 0 || iNode >= MAX_NODES)
return;
@@ -1842,16 +1904,16 @@ void cNodeMachine::danger(int iNode, int iTeam) {
// Go through all valid nodes, except iNode, and increase danger if needed.
for (int i = 0; i < MAX_NODES; i++) {
if (Nodes[i].origin != Vector(9999, 9999, 9999) && i != iNode) {
- float fDist = func_distance(Nodes[i].origin, Nodes[iNode].origin);
+ const float fDist = func_distance(Nodes[i].origin, Nodes[iNode].origin);
if (fDist < NODE_DANGER_DIST) {
//Using TraceHull to detect de_aztec bridge and other entities.
TraceResult tr;
UTIL_TraceHull(Nodes[iNode].origin, Nodes[i].origin,
- ignore_monsters, point_hull, NULL, &tr);
+ ignore_monsters, point_hull, nullptr, &tr);
// within distance and reachable
- if (tr.flFraction >= 1.0) {
- double costIncrease = (fDist / NODE_DANGER_DIST) * NODE_DANGER_STEP;
+ if (tr.flFraction >= 1.0f) {
+ const float costIncrease = fDist / NODE_DANGER_DIST * NODE_DANGER_STEP;
InfoNodes[i].fDanger[iTeam] += costIncrease;
}
}
@@ -1860,7 +1922,7 @@ void cNodeMachine::danger(int iNode, int iTeam) {
}
// Adds a new goal to the array
-void cNodeMachine::addGoal(edict_t *pEdict, int goalType, Vector vVec) {
+void cNodeMachine::addGoal(edict_t* pEdict, const int goalType, const Vector& vVec) {
//
// 14/06/04
// Be carefull with adding SERVER_PRINT messages here
@@ -1873,19 +1935,19 @@ void cNodeMachine::addGoal(edict_t *pEdict, int goalType, Vector vVec) {
return; // do not add goal that is already in our list
}
- int index = getFreeGoalIndex();
+ const int index = getFreeGoalIndex();
if (index < 0) {
return;
}
- int distance = NODE_ZONE * 2;
+ float distance = static_cast(NODE_ZONE) * 2.0f;
// some goals require very close nodes
if (goalType == GOAL_HOSTAGE ||
goalType == GOAL_VIPSAFETY ||
goalType == GOAL_RESCUEZONE ||
goalType == GOAL_BOMBSPOT) {
- distance = NODE_ZONE * 0.8;
+ distance = static_cast(NODE_ZONE) * 0.8f;
}
int nNode = getClosestNode(vVec, distance, pEdict);
@@ -1899,8 +1961,8 @@ void cNodeMachine::addGoal(edict_t *pEdict, int goalType, Vector vVec) {
}
}
- tGoal *goal = getGoal(index);
- if (goal == NULL) {
+ tGoal* goal = getGoal(index);
+ if (goal == nullptr) {
rblog("No valid goal index found - bailing\n");
return;
}
@@ -1908,18 +1970,17 @@ void cNodeMachine::addGoal(edict_t *pEdict, int goalType, Vector vVec) {
goal->index = index;
goal->pGoalEdict = pEdict;
goal->iType = goalType;
- strcpy(goal->name, getGoalTypeAsText(*goal));
+ //strcpy(goal->name, getGoalTypeAsText(*goal)); //That appears to trigger crash [APG]RoboCop[CL]
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Adding goal at index %d of type %s, with nearby node %d\n", index, goal->name, nNode);
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "Adding goal at index %d of type %s, with nearby node %d\n", index, goal->name, nNode);
rblog(msg);
}
-tGoal *cNodeMachine::getGoal(int index) {
+tGoal *cNodeMachine::getGoal(const int index) {
if (index < 0 || index >= MAX_GOALS) {
rblog("ERROR: Asking to retrieve goal with invalid index! Returning goal NULL\n");
- return NULL;
+ return nullptr;
}
// char msg[255];
// sprintf(msg, "Getting goal by index [%d]\n", index);
@@ -1934,8 +1995,7 @@ tGoal *cNodeMachine::getGoal(int index) {
*/
int cNodeMachine::getFreeGoalIndex() const {
int index = -1;
- int g = 0; // <-- ADDED BY PMB ELSE LINUX COMPILER COMPLAINS (ISO COMPLIANCE)
- for (g = 0; g < MAX_GOALS; g++) {
+ for (int g = 0; g < MAX_GOALS; g++) {
if (Goals[g].iType == GOAL_NONE) {
index = g;
break;
@@ -1951,31 +2011,28 @@ int cNodeMachine::getFreeGoalIndex() const {
* @param pEdict
* @return
*/
-bool cNodeMachine::hasGoalWithEdict(edict_t *pEdict) {
- if (pEdict == NULL) return false; // no edict == by default no
-
- for (int g = 0; g < MAX_GOALS; g++) {
- if (Goals[g].pGoalEdict == pEdict) {
- return true;
- }
- }
+bool cNodeMachine::hasGoalWithEdict(edict_t* pEdict) const
+{
+ if (pEdict == nullptr) return false; // no edict == by default no
- // Does not exist
- return false;
+ return std::any_of(std::begin(Goals), std::end(Goals), [pEdict](const tGoal& goal) {
+ return goal.pGoalEdict == pEdict;
+ });
}
void cNodeMachine::resetCheckedValuesForGoals() {
- for (int g = 0; g < MAX_GOALS; g++) {
- if (Goals[g].iChecked > 0)
- Goals[g].iChecked = 0;
+ for (tGoal& Goal : Goals)
+ {
+ Goal.iChecked = std::min(Goal.iChecked, 0);
}
}
// returns goal type from node, -1 for unknown
-int cNodeMachine::getGoalIndexFromNode(int iNode) {
- for (int g = 0; g < MAX_GOALS; g++)
- if (Goals[g].iNode == iNode)
- return Goals[g].iType;
+int cNodeMachine::getGoalIndexFromNode(const int iNode) const
+{
+ for (const tGoal& Goal : Goals)
+ if (Goal.iNode == iNode)
+ return Goal.iType;
return -1;
}
@@ -1983,8 +2040,8 @@ int cNodeMachine::getGoalIndexFromNode(int iNode) {
void cNodeMachine::updateGoals() {
rblog("cNodeMachine::updateGoals - START\n");
for (int i = 0; i < MAX_GOALS; i++) {
- tGoal *goal = getGoal(i);
- if (goal == NULL || goal->iNode < 0) continue;
+ const tGoal *goal = getGoal(i);
+ if (goal == nullptr || goal->iNode < 0) continue;
if (goal->iType == GOAL_HOSTAGE) {
initGoal(i);
@@ -1995,13 +2052,13 @@ void cNodeMachine::updateGoals() {
}
}
- edict_t *pent = NULL;
+ edict_t *pent = nullptr;
// re-add goals for hostages so we have the latest information about them
// GOAL #5 - Hostages (this is the 'starting' position):
- while ((pent = UTIL_FindEntityByClassname(pent, "hostage_entity")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "hostage_entity")) != nullptr) {
// verify hostage is still rescueable
- if (isHostageRescued(NULL, pent) || !FUNC_EdictIsAlive(pent)) {
+ if (isHostageRescued(nullptr, pent) || !FUNC_EdictIsAlive(pent)) {
continue; // skip dead or already rescued hostages
}
@@ -2010,17 +2067,15 @@ void cNodeMachine::updateGoals() {
// SEARCH PLAYERS FOR ENEMIES
for (int i = 1; i <= gpGlobals->maxClients; i++) {
- edict_t *pPlayer = INDEXENT(i);
-
+ edict_t* pPlayer = INDEXENT(i);
+
// skip invalid players and skip self (i.e. this bot)
- if ((pPlayer) && (!pPlayer->free)) {
+ if (pPlayer && !pPlayer->free) {
// skip this player if not alive (i.e. dead or dying)
- if (!IsAlive(pPlayer))
- continue;
- }
-
- if (UTIL_IsVip(pPlayer)) {
- addGoal(pPlayer, GOAL_VIP, pPlayer->v.origin + Vector(0,0,32));
+ if (!IsAlive(pPlayer)) continue;
+ if (UTIL_IsVip(pPlayer)) {
+ addGoal(pPlayer, GOAL_VIP, pPlayer->v.origin + Vector(0, 0, 32));
+ }
}
}
rblog("cNodeMachine::updateGoals - FINISHED\n");
@@ -2039,61 +2094,61 @@ void cNodeMachine::setUpInitialGoals() {
// because Nodes get expanded all the time the bot should eventually learn
// how to reach other goals.
- edict_t *pent = NULL;
+ edict_t *pent = nullptr;
// GOAL #1 - Counter Terrorist Spawn points.
- while ((pent = UTIL_FindEntityByClassname(pent, "info_player_start")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "info_player_start")) != nullptr) {
addGoal(pent, GOAL_SPAWNCT, pent->v.origin);
}
// GOAL #2 - Terrorist Spawn points.
- while ((pent = UTIL_FindEntityByClassname(pent, "info_player_deathmatch")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "info_player_deathmatch")) != nullptr) {
addGoal(pent, GOAL_SPAWNT, pent->v.origin);
}
// GOAL #3 - Hostage rescue zone
- while ((pent = UTIL_FindEntityByClassname(pent, "func_hostage_rescue")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "func_hostage_rescue")) != nullptr) {
addGoal(pent, GOAL_RESCUEZONE, VecBModelOrigin(pent));
}
// rescue zone can also be an entity of info_hostage_rescue
- while ((pent = UTIL_FindEntityByClassname(pent, "info_hostage_rescue")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "info_hostage_rescue")) != nullptr) {
addGoal(pent, GOAL_RESCUEZONE, VecBModelOrigin(pent));
}
// GOAL #4 - Bombspot zone
// Bomb spot
- while ((pent = UTIL_FindEntityByClassname(pent, "func_bomb_target")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "func_bomb_target")) != nullptr) {
addGoal(pent, GOAL_BOMBSPOT, VecBModelOrigin(pent));
}
- while ((pent = UTIL_FindEntityByClassname(pent, "info_bomb_target")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "info_bomb_target")) != nullptr) {
addGoal(pent, GOAL_BOMBSPOT, VecBModelOrigin(pent));
}
// GOAL #5 - Hostages (this is the 'starting' position):
- while ((pent = UTIL_FindEntityByClassname(pent, "hostage_entity")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "hostage_entity")) != nullptr) {
addGoal(pent, GOAL_HOSTAGE, pent->v.origin + Vector(0,0,32));
}
// GOAL #6 - VIP (this is the 'starting' position) (EVY)
- while ((pent = UTIL_FindEntityByClassname(pent, "info_vip_start")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "info_vip_start")) != nullptr) {
addGoal(pent, GOAL_VIP, VecBModelOrigin(pent));
}
// GOAL #7 - VIP safety (this is the 'rescue' position) (EVY)
- while ((pent = UTIL_FindEntityByClassname(pent, "func_vip_safetyzone")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "func_vip_safetyzone")) != nullptr) {
addGoal(pent, GOAL_VIPSAFETY, VecBModelOrigin(pent));
}
// GOAL #8 - Escape zone for es_ (EVY)
- while ((pent = UTIL_FindEntityByClassname(pent, "func_escapezone")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "func_escapezone")) != nullptr) {
addGoal(pent, GOAL_ESCAPEZONE, VecBModelOrigin(pent));
}
// 05/07/04
// GOAL #9 - Free weapons on the ground EVY
- while ((pent = UTIL_FindEntityByClassname(pent, "armoury_entity")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "armoury_entity")) != nullptr) {
addGoal(pent, GOAL_WEAPON, VecBModelOrigin(pent));
}
@@ -2103,37 +2158,29 @@ void cNodeMachine::setUpInitialGoals() {
}
// Find a goal, and return the node close to it
-tGoal *cNodeMachine::getRandomGoalByType(int goalType) {
+tGoal* cNodeMachine::getRandomGoalByType(const int goalType) {
if (goalType == GOAL_NONE)
- return NULL;
-
- int possibleGoalNodes[MAX_GOALS];
- for (int c = 0; c < MAX_GOALS; c++) {
- possibleGoalNodes[c] = -1;
- }
+ return nullptr;
- int possibleCandidateIndex = 0;
- for (int goalIndex = 0; goalIndex < MAX_GOALS; goalIndex++) {
- if (Goals[goalIndex].iType == goalType && // type equals requested type
- Goals[goalIndex].iNode > -1) { // and it has a node
-// possibleGoalNodes[possibleCandidateIndex] = Goals[goalIndex].iNode;
- possibleGoalNodes[possibleCandidateIndex] = goalIndex;
- possibleCandidateIndex++;
+ std::vector possibleGoalIndices;
+ for (int goalIndex = 0; goalIndex < MAX_GOALS; ++goalIndex) {
+ if (Goals[goalIndex].iType == goalType && Goals[goalIndex].iNode > -1) {
+ possibleGoalIndices.push_back(goalIndex);
}
}
- if (possibleCandidateIndex == 0)
- return NULL; // nothing found :(
+ if (possibleGoalIndices.empty())
+ return nullptr;
- // we have an amount of goals, pick one randomly
- int randomGoalIndex = RANDOM_LONG(0, (possibleCandidateIndex - 1));
+ const int randomIndex = RANDOM_LONG(0, static_cast(possibleGoalIndices.size()) - 1);
+ const int chosenGoalIndex = possibleGoalIndices[randomIndex];
char msg[255];
- sprintf(msg, "cNodeMachine::getRandomGoalByType() - Found %d nodes of type %d and picked %d\n",
- possibleCandidateIndex, goalType, randomGoalIndex);
+ snprintf(msg, sizeof(msg), "cNodeMachine::getRandomGoalByType() - Found %zu nodes of type %d and picked index %d (goal %d)\n",
+ possibleGoalIndices.size(), goalType, randomIndex, chosenGoalIndex);
rblog(msg);
- return getGoal(randomGoalIndex);
+ return getGoal(chosenGoalIndex);
}
// Contact scaler (on round start)
@@ -2142,22 +2189,21 @@ void cNodeMachine::scale_contact() {
// rescale all other values to stay correct.
int iTeam = 0;
while (iTeam < 2) {
- float fHighest = 0.0;
- int i = 0; // <-- ADDED BY PMB ELSE LINUX COMPILER ISNT HAPPY
+ float fHighest = 0.0f;
+ int i; // <-- ADDED BY PMB ELSE LINUX COMPILER ISNT HAPPY
for (i = 0; i < MAX_NODES; i++)
- if (InfoNodes[i].fContact[iTeam] > fHighest)
- fHighest = InfoNodes[i].fContact[iTeam];
+ fHighest = std::max(InfoNodes[i].fContact[iTeam], fHighest);
- if (fHighest < 1.0) {
+ if (fHighest < 1.0f) {
iTeam++;
continue; // no need to rescale
}
// Check how much we passed the limit
- float fLimit = 1.0 / fHighest;
+ const float fLimit = 1.0f / fHighest;
// Now rescale all
for (i = 0; i < MAX_NODES; i++)
- if (InfoNodes[i].fContact[iTeam] > 0.0)
+ if (InfoNodes[i].fContact[iTeam] > 0.0f)
InfoNodes[i].fContact[iTeam] *= fLimit; // rescale
iTeam++;
@@ -2172,22 +2218,21 @@ void cNodeMachine::scale_danger() {
// rescale all other danger values to stay correct.
int iTeam = 0;
while (iTeam < 2) {
- float fHighest = 0.0;
- int i = 0; // ADDED BY PMB FOR COMPILING UNDER LINUX
+ float fHighest = 0.0f;
+ int i; // ADDED BY PMB FOR COMPILING UNDER LINUX
for (i = 0; i < MAX_NODES; i++)
- if (InfoNodes[i].fDanger[iTeam] > fHighest)
- fHighest = InfoNodes[i].fDanger[iTeam];
+ fHighest = std::max(InfoNodes[i].fDanger[iTeam], fHighest);
- if (fHighest < 0.8) {
+ if (fHighest < 0.8f) {
iTeam++;
continue; // no need to rescale
}
// Check how much we passed the limit
- float fLimit = 0.7 / fHighest;
+ const float fLimit = 0.7f / fHighest;
// Now rescale all
for (i = 0; i < MAX_NODES; i++)
- if (InfoNodes[i].fDanger[iTeam] > 0.0)
+ if (InfoNodes[i].fDanger[iTeam] > 0.0f)
InfoNodes[i].fDanger[iTeam] *= fLimit; // rescale
iTeam++;
@@ -2197,109 +2242,91 @@ void cNodeMachine::scale_danger() {
}
// Pathfinder
-bool cNodeMachine::createPath(int nodeStartIndex, int nodeTargetIndex, int botIndex, cBot *pBot, int iFlags) {
+bool cNodeMachine::createPath(const int nodeStartIndex, const int nodeTargetIndex, const int botIndex, cBot* pBot, int iFlags) {
// Will create a path from nodeStartIndex to nodeTargetIndex, and store it into index number iPathId
if (pBot) {
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "createPath(from->%d, to->%d, botIndex->%d)", nodeStartIndex, nodeTargetIndex, botIndex);
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "createPath(from->%d, to->%d, botIndex->%d)", nodeStartIndex, nodeTargetIndex, botIndex);
pBot->rprint("cNodeMachine::createPath", msg);
}
- if (nodeStartIndex < 0 || nodeTargetIndex < 0 || botIndex < 0)
+ if (nodeStartIndex < 0 || nodeTargetIndex < 0 || botIndex < 0 ||
+ nodeStartIndex >= MAX_NODES || nodeTargetIndex >= MAX_NODES) {
return false; // do not create a path when invalid params given
+ }
if (nodeStartIndex > iMaxUsedNodes || nodeTargetIndex > iMaxUsedNodes)
return false; // do not create a path when invalid params given
- int botTeam = -1;
if (pBot) {
- botTeam = UTIL_GetTeam(pBot->pEdict); // Stefan: yes we use 0-1 based, not 1-2 based
+ UTIL_GetTeam(pBot->pEdict); // Stefan: yes we use 0-1 based, not 1-2 based
}
- const Vector &INVALID_VECTOR = Vector(9999, 9999, 9999);
-
- // start or target vector may not be invalid
if (Nodes[nodeStartIndex].origin == INVALID_VECTOR ||
Nodes[nodeTargetIndex].origin == INVALID_VECTOR) {
rblog("Invalid start and target index\n");
return false;
}
- int path_index = 0, nodeIndex;
-
path_clear(botIndex);
- // INIT: Start
- makeAllWaypointsAvailable();
-
- // Our start waypoint is open
- float gCost = 0.0f; // distance from starting node
- float hCost = func_distance(Nodes[nodeStartIndex].origin,
- Nodes[nodeTargetIndex].origin); // distance from end node to node
- float cost = gCost + hCost;
- closeNode(nodeStartIndex, nodeStartIndex, cost);
- openNeighbourNodes(nodeStartIndex, nodeStartIndex, nodeTargetIndex, -1);
-
- bool pathFound = false; // is it still valid to loop through the lists for pathfinding?
-
- int nodesEvaluated = 0;
- // INIT: End
- // PATHFINDER: Start
- while (!pathFound) {
- float lowestScore = 99999999.0f;
- int nodeToClose = -1;
-
- // go through all OPEN waypoints
- for (nodeIndex = 0; nodeIndex < MAX_NODES; nodeIndex++) {
- tNodestar &nodeStar = astar_list[nodeIndex];
-
- if (nodeStar.state == CLOSED || nodeStar.state == AVAILABLE) continue;
-
- // OPEN waypoint
- tNode &node = Nodes[nodeIndex];
- if (node.origin == INVALID_VECTOR) {
- rblog("Evaluating an INVALID vector!?!\n");
- nodeStar.state = CLOSED;
- continue; // it is an invalid vector
- }
+ std::priority_queue openList;
+ std::vector nodeData(MAX_NODES);
- // nodeIndex is target, so target found
- if (nodeIndex == nodeTargetIndex) {
- pathFound = true;
- rblog("Target found\n");
- break; // Get out of here
- }
+ // Initialize node data
+ for (int i = 0; i < MAX_NODES; ++i) {
+ nodeData[i].state = AVAILABLE;
+ nodeData[i].parent = -1;
+ nodeData[i].cost = std::numeric_limits::max();
+ }
- // open is not target, so go over its neighbours (which have been opened) and find the lowest cost
- if (nodeStar.cost < lowestScore) {
- nodeToClose = nodeIndex;
- lowestScore = nodeStar.cost;
- }
+ // Setup start node
+ nodeData[nodeStartIndex].cost = func_distance(Nodes[nodeStartIndex].origin, Nodes[nodeTargetIndex].origin);
+ nodeData[nodeStartIndex].state = OPEN;
+ openList.push({ OPEN, nodeStartIndex, nodeData[nodeStartIndex].cost, 0.0f });
+
+ bool pathFound = false;
+
+ while (!openList.empty()) {
+ const int currentNodeIndex = openList.top().parent;
+ openList.pop();
+
+ if (nodeData[currentNodeIndex].state == CLOSED) {
+ continue;
}
- // a node that should be closed is an evaluated node and the most preferred one.
- // open up all neighbouring nodes, and close this one
- if (nodeToClose > -1) {
-// char msg[255];
-// sprintf(msg, "Found node to close [%d]\n", nodeToClose);
-// rblog(msg);
- astar_list[nodeToClose].state = CLOSED;
- int botTeam = -1;
+ if (currentNodeIndex == nodeTargetIndex) {
+ pathFound = true;
+ break;
+ }
+
+ nodeData[currentNodeIndex].state = CLOSED;
+
+ const tNode& currentNode = Nodes[currentNodeIndex];
+ for (const int neighborIndex : currentNode.iNeighbour) {
+ if (neighborIndex < 0 || Nodes[neighborIndex].origin == INVALID_VECTOR || nodeData[neighborIndex].state == CLOSED) {
+ continue;
+ }
+
+ const float gCost = nodeData[currentNodeIndex].cost + func_distance(currentNode.origin, Nodes[neighborIndex].origin);
+ const float hCost = func_distance(Nodes[neighborIndex].origin, Nodes[nodeTargetIndex].origin);
+ float totalCost = gCost + hCost;
+
if (pBot) {
- botTeam = pBot->iTeam;
+ const float dangerCost = InfoNodes[neighborIndex].fDanger[pBot->iTeam] * totalCost;
+ totalCost += dangerCost;
}
- openNeighbourNodes(nodeStartIndex, nodeToClose, nodeTargetIndex, botTeam);
- } else {
-// rblog("Did not find any open waypoint\n");
- break;
+ if (totalCost < nodeData[neighborIndex].cost) {
+ nodeData[neighborIndex].parent = currentNodeIndex;
+ nodeData[neighborIndex].cost = totalCost;
+ nodeData[neighborIndex].state = OPEN;
+ openList.push({ OPEN, neighborIndex, totalCost, 0.0f });
+ }
}
}
- // PATHFINDER: End
- // RESULT: Success
if (!pathFound) {
if (pBot) {
pBot->rprint("cNodeMachine::createPath", "Failed to create path");
@@ -2307,100 +2334,33 @@ bool cNodeMachine::createPath(int nodeStartIndex, int nodeTargetIndex, int botIn
return false;
}
- for (nodeIndex = 0; nodeIndex < MAX_PATH_NODES; nodeIndex++) {
-
- tNodestar &nodeStar = astar_list[nodeIndex];
- if (nodeStar.state == AVAILABLE) continue;
-
-// char msg[255];
-// memset(msg, 0, sizeof(msg));
-// if (nodeStar.state == CLOSED) {
-// sprintf(msg, "Node [%d] is CLOSED. Cost = %f. Parent = %d\n", nodeIndex, nodeStar.cost, nodeStar.parent);
-// } else if (nodeStar.state == OPEN) {
-// sprintf(msg, "Node [%d] is OPEN. Cost = %f. Parent = %d\n", nodeIndex, nodeStar.cost, nodeStar.parent);
-// }
-// rblog(msg);
- }
-
- // Build path (from goal to start, read out parent waypoint to backtrace)
- int temp_path[MAX_PATH_NODES];
-
- // INIT: Start
- for (nodeIndex = 0; nodeIndex < MAX_PATH_NODES; nodeIndex++)
- temp_path[nodeIndex] = -1;
-
- // The path has been built yet?
- bool built = false;
-
- // The variables needed to backtrace
- // wpta = waypoint we use to backtrace (starting at goal)
- // p = index for temp_path (the path will be GOAL-START, reversed later)
- int wpta = nodeTargetIndex, p = 0;
-
- // INIT: End
-
- // START: When path is not built yet
- while (!built) {
- temp_path[p] = wpta; // Copy the waypoint into temp_path[index]
-
- // IF: At current (start) waypoint
- if (wpta == nodeStartIndex) {
- // Check if we did not already had this waypoint before
- built = true; // We finished building this path.
- } else {
- // Whenever wpta is containing bad information...
- if (wpta < 0 || wpta > MAX_NODES)
- break; // ...get out aswell
- }
-
- // waypoint we use to backtrace will be set to parent waypoint.
- wpta = astar_list[wpta].parent;
-
- // Increase index for temp_path
- p++;
-
- // Whenever we reach the limit, get out.
- if (p >= MAX_PATH_NODES)
- break;
-
+ // Build path
+ std::vector temp_path;
+ int wpta = nodeTargetIndex;
+ while (wpta != -1) {
+ temp_path.push_back(wpta);
+ wpta = nodeData[wpta].parent;
}
- // INIT: Start
- path_index = 0; // done above, but done again to be sure
- // INIT: End
-
- // Now set the path up correctly
- for (nodeIndex = (MAX_NODES - 1); nodeIndex > -1; nodeIndex--) {
- int node = temp_path[nodeIndex];
- if (node < 0)
- continue;
-
- iPath[botIndex][path_index] = node;
+ std::reverse(temp_path.begin(), temp_path.end());
- // print out full path so we know what the order is
- if (pBot != NULL) {
- char pathMsg[255];
- memset(pathMsg, 0, sizeof(pathMsg));
- sprintf(pathMsg, "Bot [%d] path index [%d] has node [%d]", botIndex, path_index, node);
+ // Copy to bot's path array
+ for (size_t i = 0; i < temp_path.size() && i < MAX_PATH_NODES; ++i) {
+ iPath[botIndex][i] = temp_path[i];
+ if (pBot) {
+ char pathMsg[255] = {};
+ snprintf(pathMsg, sizeof(pathMsg), "Bot [%d] path index [%zu] has node [%d]", botIndex, i, temp_path[i]);
pBot->rprint("cNodeMachine::createPath", pathMsg);
}
-
- path_index++;
}
- // Finally there is the goal
- iPath[botIndex][path_index] = nodeTargetIndex;
-
- // terminate path
- path_index++;
- iPath[botIndex][path_index] = -1;
-
// And set bot in motion
- if (pBot != NULL) {
+ if (pBot != nullptr) {
pBot->beginWalkingPath();
pBot->setTimeToMoveToNode(2); // set timer (how much time do we allow ourselves to reach the following node)
pBot->rprint("cNodeMachine::createPath", "Path creation finished successfully");
- } else {
+ }
+ else {
rblog("createPath (without bot) - path creation finished\n");
}
@@ -2413,7 +2373,7 @@ bool cNodeMachine::createPath(int nodeStartIndex, int nodeTargetIndex, int botIn
* @param parent
* @param cost
*/
-void cNodeMachine::closeNode(int nodeIndex, int parent, float cost) {
+void cNodeMachine::closeNode(const int nodeIndex, const int parent, const float cost) {
astar_list[nodeIndex].state = CLOSED;
astar_list[nodeIndex].parent = parent;
astar_list[nodeIndex].cost = cost;
@@ -2421,27 +2381,32 @@ void cNodeMachine::closeNode(int nodeIndex, int parent, float cost) {
/**
* Open all neighbouring nodes, calculate costs for each neighbouring node
+ * @param startNodeIndex
+ * @param nodeToOpenNeighboursFrom
+ * @param destinationNodeIndex
+ * @param botTeam
* @param nodeStartIndex
* @param parent
* @param cost
*/
-void cNodeMachine::openNeighbourNodes(int startNodeIndex, int nodeToOpenNeighboursFrom, int destinationNodeIndex, int botTeam) {
- tNode &startNode = Nodes[startNodeIndex]; // very start of path
- tNode &destNode = Nodes[destinationNodeIndex]; // destination for path
+void cNodeMachine::openNeighbourNodes(const int startNodeIndex, const int nodeToOpenNeighboursFrom, const int destinationNodeIndex, const int botTeam) const
+{
+ const tNode &startNode = Nodes[startNodeIndex]; // very start of path
+ const tNode &destNode = Nodes[destinationNodeIndex]; // destination for path
- tNode &node = Nodes[nodeToOpenNeighboursFrom]; // node evaluating neighbours
+ const tNode &node = Nodes[nodeToOpenNeighboursFrom]; // node evaluating neighbours
- for (int i = 0; i < MAX_NEIGHBOURS; i++) {
- int neighbourNode = node.iNeighbour[i];
- if (neighbourNode < 0) continue; // skip invalid nodes
+ for (const int neighbourNode : node.iNeighbour)
+ {
+ if (neighbourNode < 0) continue; // skip invalid nodes
if (Nodes[neighbourNode].origin == INVALID_VECTOR) continue; // skip nodes with invalid vector
- float gCost = func_distance(startNode.origin, destNode.origin); // distance from starting node
- float hCost = func_distance(node.origin, destNode.origin); // distance from end node to node
+ const float gCost = func_distance(startNode.origin, destNode.origin); // distance from starting node
+ const float hCost = func_distance(node.origin, destNode.origin); // distance from end node to node
float cost = gCost + hCost;
if (botTeam > -1) {
- double dangerCost = InfoNodes[neighbourNode].fDanger[botTeam] * cost;
+ const float dangerCost = InfoNodes[neighbourNode].fDanger[botTeam] * cost;
// double contactCost = InfoNodes[neighbourNode].fContact[botTeam] * cost;
cost += dangerCost;
@@ -2465,44 +2430,113 @@ void cNodeMachine::openNeighbourNodes(int startNodeIndex, int nodeToOpenNeighbou
// rblog(msg);
nodeStar.parent = nodeToOpenNeighboursFrom;
nodeStar.cost = cost;
- }
+ }
}
- }
+ }
}
/**
* This marks all waypoints to be available to be evaluated again
* @param nodeIndex
*/
-void cNodeMachine::makeAllWaypointsAvailable() const {
- int nodeIndex = 0;
- for (nodeIndex = 0; nodeIndex < MAX_NODES; nodeIndex++) {
- astar_list[nodeIndex].cost = 0;
- astar_list[nodeIndex].parent = -1;
- astar_list[nodeIndex].state = AVAILABLE;
+void cNodeMachine::makeAllWaypointsAvailable()
+{
+ for (tNodestar& nodeIndex : astar_list)
+ {
+ nodeIndex.cost = 0;
+ nodeIndex.parent = -1;
+ nodeIndex.state = AVAILABLE;
}
// rblog("All nodes set to AVAILABLE\n");
}
+bool cNodeMachine::isValidNodeIndex(const int index) //TODO: Experimental [APG]RoboCop[CL]
+{
+ return index >= 0 && index < MAX_NODES;
+}
+
+bool cNodeMachine::isInvalidNode(const int index) //TODO: Experimental [APG]RoboCop[CL]
+{
+ return !isValidNodeIndex(index);
+}
+
+//TODO: Experimental [APG]RoboCop[CL]
+void cNodeMachine::buildPath(const int nodeStartIndex, const int nodeTargetIndex, const int botIndex, cBot* pBot)
+{
+ if (!isValidNodeIndex(nodeStartIndex) || !isValidNodeIndex(nodeTargetIndex)) {
+ rblog("Invalid node index provided to buildPath");
+ return;
+ }
+
+ // Clear the current path for the bot
+ path_clear(botIndex);
+
+ // Initialize the A* algorithm
+ std::priority_queue openList;
+ std::unordered_map closedList;
+
+ constexpr tNodestar startNode = { OPEN, -1, 0.0f, 0.0 };
+ openList.push(startNode);
+
+ while (!openList.empty()) {
+ tNodestar currentNode = openList.top();
+ openList.pop();
+
+ if (currentNode.state == CLOSED) {
+ continue;
+ }
+
+ if (currentNode.parent == nodeTargetIndex) {
+ // Path found, reconstruct the path
+ int pathIndex = 0;
+ while (currentNode.parent != -1) {
+ iPath[botIndex][pathIndex++] = currentNode.parent;
+ currentNode = closedList[currentNode.parent];
+ }
+ std::reverse(iPath[botIndex], iPath[botIndex] + pathIndex);
+ return;
+ }
+
+ currentNode.state = CLOSED;
+ closedList[currentNode.parent] = currentNode;
+
+ // Open neighbor nodes
+ for (int neighborIndex : Nodes[currentNode.parent].iNeighbour)
+ {
+ if (neighborIndex == -1 || closedList.find(neighborIndex) != closedList.end()) {
+ continue;
+ }
+
+ const float cost = currentNode.cost + (node_vector(currentNode.parent) - node_vector(neighborIndex)).Length();
+ tNodestar neighborNode = { OPEN, currentNode.parent, cost, 0.0 };
+ openList.push(neighborNode);
+ }
+ }
+
+ rblog("Failed to build path");
+}
+
// Find a node which has almost no danger!
-int cNodeMachine::node_camp(Vector vOrigin, int iTeam) {
+int cNodeMachine::node_camp(const Vector& vOrigin, const int iTeam) const
+{
// Use Meredians to search for nodes
int iX, iY;
VectorToMeredian(vOrigin, &iX, &iY);
- float fDanger = 2.0;
- float fDistance = 9999;
- int iVisibility = 9999;
int iBestNode = -1;
// Theory:
// Find a node, close, and less danger...
// and with less visibility
- if (iX > -1 && iY > -1) {
- // Search in this meredian
- for (int i = 0; i < MAX_NODES_IN_MEREDIANS; i++)
- if (Meredians[iX][iY].iNodes[i] > -1) {
- int iNode = Meredians[iX][iY].iNodes[i];
+ if (iX > -1 && iY > -1)
+ {
+ int iVisibility = 9999;
+ float fDistance = 9999.0f;
+ float fDanger = 2.0f;
+ // Search in this meredian
+ for (const int i : Meredians[iX][iY].iNodes)
+ if (i > -1) {
+ const int iNode = i;
if (Nodes[iNode].iNodeBits & BIT_WATER)
continue; // next node, do not camp under water!
@@ -2531,51 +2565,50 @@ int cNodeMachine::node_camp(Vector vOrigin, int iTeam) {
}
return iBestNode;
-
}
// Check if iFrom is visible from other nodes (and opposite)
-void cNodeMachine::vis_calculate(int iFrom) {
+void cNodeMachine::vis_calculate(const int iFrom) {
// Check around your area to see what is visible
- float fClosest = 1024;
- for (int i = 0; i < MAX_NODES; i++)
- if ((i != iFrom) && (Nodes[i].origin != Vector(9999, 9999, 9999))) {
- float fDistance = func_distance(Nodes[i].origin, Nodes[iFrom].origin);
- if (fDistance < fClosest) {
- TraceResult tr;
+ constexpr float MAX_VISIBILITY_DISTANCE = 1024.0f;
+ for (int i = 0; i < iMaxUsedNodes; ++i) {
+ if (i == iFrom || Nodes[i].origin == INVALID_VECTOR) {
+ continue; // Skip the current node or invalid nodes
+ }
- // Visibility is not yet calculated, so determine now
- if (GetVisibilityFromTo(iFrom, i) == VIS_UNKNOWN) // BERKED
- {
- UTIL_TraceHull(Nodes[iFrom].origin, Nodes[i].origin, ignore_monsters, point_hull, NULL, &tr);
+ const float fDistance = func_distance(Nodes[i].origin, Nodes[iFrom].origin);
+ if (fDistance >= MAX_VISIBILITY_DISTANCE) {
+ continue; // Skip if the node is too far
+ }
- if (tr.flFraction < 1.0) {
- SetVisibilityFromTo(iFrom, i, false);
- SetVisibilityFromTo(i, iFrom, false);
- } else {
- SetVisibilityFromTo(iFrom, i, true);
- SetVisibilityFromTo(i, iFrom, true);
- }
- }
- }
+ // Visibility is not yet calculated, so determine now
+ if (GetVisibilityFromTo(iFrom, i) == VIS_UNKNOWN) {
+ TraceResult tr;
+
+ UTIL_TraceHull(Nodes[iFrom].origin, Nodes[i].origin, ignore_monsters, point_hull, nullptr, &tr);
+ const bool isVisible = (tr.flFraction >= 1.0f);
+ SetVisibilityFromTo(iFrom, i, isVisible);
+ SetVisibilityFromTo(i, iFrom, isVisible);
}
+ }
}
// Find a node to look at when camping
-int cNodeMachine::node_look_camp(Vector vOrigin, int iTeam,
- edict_t *pEdict) {
+int cNodeMachine::node_look_camp(const Vector& vOrigin, const int iTeam, edict_t *pEdict) {
rblog("node_look_camp - start\n");
- float fDanger = -0.1;
+ float fDanger = -0.1f;
float fDistance = 0;
int iBestNode = -2;
// Theory:
// Find a node, far, and a lot danger...
- int iFrom = getClosestNode(vOrigin, 75, pEdict);
+ // and with less visibility
+
+ const int iFrom = getClosestNode(vOrigin, 75, pEdict);
// Search in this meredian
for (int i = 0; i < MAX_NODES; i++) {
- int iNode = i;
+ const int iNode = i;
if (InfoNodes[iNode].fDanger[iTeam] > fDanger)
if (func_distance(vOrigin, Nodes[iNode].origin) > fDistance) {
// all nodes within this range may be tracelined
@@ -2586,16 +2619,12 @@ int cNodeMachine::node_look_camp(Vector vOrigin, int iTeam,
UTIL_TraceLine(Nodes[iFrom].origin, Nodes[iNode].origin,
ignore_monsters, ignore_glass, pEdict, &tr);
//UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "NODE, MEREDIAN: VISIBILITY NOT KNOWN \n");
- if (tr.flFraction < 1.0) {
+ if (tr.flFraction < 1.0f) {
bVisible = false;
// Set to false
SetVisibilityFromTo(iFrom, iNode, false);
SetVisibilityFromTo(iNode, iFrom, false);
- } else {
- SetVisibilityFromTo(iFrom, iNode, true);
- SetVisibilityFromTo(iNode, iFrom, true);
}
-
} else {
if (GetVisibilityFromTo(iFrom, iNode) == VIS_BLOCKED) // BERKED
{
@@ -2614,7 +2643,7 @@ int cNodeMachine::node_look_camp(Vector vOrigin, int iTeam,
}
}
char msg[255];
- sprintf(msg, "Found best node to camp at %d\n", iBestNode);
+ snprintf(msg, sizeof(msg), "Found best node to camp at %d\n", iBestNode);
rblog(msg);
return iBestNode;
}
@@ -2625,9 +2654,9 @@ int cNodeMachine::node_look_camp(Vector vOrigin, int iTeam,
* @param pBot
* @param distanceMoved
*/
-void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
+void cNodeMachine::path_walk(cBot *pBot, const float distanceMoved) {
pBot->rprint("cNodeMachine::path_walk", "START");
- int BotIndex = pBot->iBotIndex;
+ const int BotIndex = pBot->iBotIndex;
// Check if path is valid
if (iPath[BotIndex][0] < 0) {
@@ -2656,25 +2685,25 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
pBot->setMoveSpeed(pBot->f_max_speed);
// Walk the path
- int currentNodeToHeadFor = pBot->getCurrentPathNodeToHeadFor(); // Node we are heading for
+ const int currentNodeToHeadFor = pBot->getCurrentPathNodeToHeadFor(); // Node we are heading to
// possibly end of path reached, overshoot destination?
if (currentNodeToHeadFor < 0) {
pBot->rprint_trace("cNodeMachine::path_walk", "Finished - there is no current node to head for");
pBot->forgetGoal();
- pBot->forgetPath();
+ pBot->stopMoving();
return;
}
// when pButtonEdict is filled in, we check if we are close!
if (pBot->pButtonEdict) {
pBot->rprint("cNodeMachine::path_walk", "Interacting with button logic");
- Vector vButtonVector = VecBModelOrigin(pBot->pButtonEdict);
+ const Vector vButtonVector = VecBModelOrigin(pBot->pButtonEdict);
float fDistance = 90;
bool bTrigger = false;
- if (strcmp(STRING(pBot->pButtonEdict->v.classname), "trigger_multiple") == 0) {
+ if (std::strcmp(STRING(pBot->pButtonEdict->v.classname), "trigger_multiple") == 0) {
fDistance = 32;
bTrigger = true;
}
@@ -2688,19 +2717,18 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
pBot->pEdict, &trb);
} else {
UTIL_TraceLine(pBot->pEdict->v.origin, vButtonVector,
- ignore_monsters, dont_ignore_glass,
- pBot->pEdict, &trb);
+ ignore_monsters, dont_ignore_glass, pBot->pEdict, &trb);
}
bool isGood = false;
// if nothing hit:
- if (trb.flFraction >= 1.0)
+ if (trb.flFraction >= 1.0f) {
+ isGood = true;
+ }
+ // we hit this button we check for
+ if (trb.pHit == pBot->pButtonEdict) {
isGood = true;
- else {
- // we hit this button we check for
- if (trb.pHit == pBot->pButtonEdict)
- isGood = true;
}
if (isGood || bTrigger) {
@@ -2708,7 +2736,7 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
pBot->vBody = pBot->vHead;
// kill edict in memory
- pBot->pButtonEdict = NULL;
+ pBot->pButtonEdict = nullptr;
// press use
if (!bTrigger)
@@ -2717,8 +2745,8 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
pBot->rprint_trace("cNodeMachine::path_walk", "This is the button I was looking for, it is close and I can use it");
// wait a little
- pBot->setTimeToWait(0.5);
- pBot->fButtonTime = gpGlobals->time + 5.0;
+ pBot->setTimeToWait(0.5f);
+ pBot->fButtonTime = gpGlobals->time + 5.0f;
pBot->setTimeToMoveToNode(3);
pBot->forgetPath();
return;
@@ -2747,11 +2775,11 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
}
// Near Node
- bool bNearNode = false;
+ bool bNearNode; //Variable Reassigned [APG]RoboCop[CL]
if (pBot->isOnLadder()) {
pBot->rprint("Bot is on ladder");
// Set touch radius
- pBot->f_strafe_speed = 0.0; // we may not strafe
+ pBot->f_strafe_speed = 0.0f; // we may not strafe
pBot->setMoveSpeed(pBot->f_max_speed / 2);
//pBot->pEdict->v.button |= IN_DUCK; // duck
@@ -2764,7 +2792,7 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
if (BotShouldDuck(pBot)) {
UTIL_BotPressKey(pBot, IN_DUCK);
- pBot->f_hold_duck = gpGlobals->time + 0.2;
+ pBot->f_hold_duck = gpGlobals->time + 0.2f;
}
bNearNode = pBot->getDistanceToNextNode() < 25;
@@ -2783,7 +2811,7 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
tGoal *goalData = pBot->getGoalData();
if (goalData) {
char msg[255];
- sprintf(msg, "Heading for goal node of type [%s]", goalData->name);
+ snprintf(msg, sizeof(msg), "Heading for goal node of type [%s]", goalData->name);
pBot->rprint_trace("cNodeMachine::path_walk (bNear)", msg);
if (goalData->iType == GOAL_HOSTAGE) {
pBot->rprint_normal("cNodeMachine::path_walk (bNear)", "next node is destination and GOAL_HOSTAGE, so need to get really close");
@@ -2799,7 +2827,9 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
}
char msg[255];
- sprintf(msg, "Heading for node %d, required distance is %f, actual distance is %f, time remaining %f", pBot->getCurrentPathNodeToHeadFor(), requiredDistance, pBot->getDistanceToNextNode(), pBot->getMoveToNodeTimeRemaining());
+ snprintf(msg, sizeof(msg), "Heading for node %d, required distance is %f, actual distance is %f, time remaining %f",
+ pBot->getCurrentPathNodeToHeadFor(), requiredDistance, pBot->getDistanceToNextNode(),
+ pBot->getMoveToNodeTimeRemaining());
pBot->rprint_trace("cNodeMachine::path_walk (bNear)", msg);
bNearNode = pBot->getDistanceToNextNode() < requiredDistance;
@@ -2807,22 +2837,22 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
// If we should duck, duck.
if (BotShouldDuck(pBot)) {
UTIL_BotPressKey(pBot, IN_DUCK);
- pBot->f_hold_duck = gpGlobals->time + 0.2;
+ pBot->f_hold_duck = gpGlobals->time + 0.2f;
}
}
- bool shouldDrawWaypointBeamsFromBot = false;
+ // No longer required? [APG]RoboCop[CL]
+ /*bool shouldDrawWaypointBeamsFromBot = false;
+
if (shouldDrawWaypointBeamsFromBot) {
- tNode *nodeHeadingFor = this->getNode(currentNodeToHeadFor);
+ const tNode *nodeHeadingFor = this->getNode(currentNodeToHeadFor);
- int player_index = 0;
- for (player_index = 1; player_index <= gpGlobals->maxClients;
- player_index++) {
+ for (int player_index = 1; player_index <= gpGlobals->maxClients;
+ player_index++) {
edict_t *pPlayer = INDEXENT(player_index);
if (pPlayer && !pPlayer->free) {
- if (FBitSet(pPlayer->v.flags, FL_CLIENT) &&
- shouldDrawWaypointBeamsFromBot) { // do not draw for now
+ if (FBitSet(pPlayer->v.flags, FL_CLIENT)) { // do not draw for now
DrawBeam(
pPlayer, // player sees beam
@@ -2831,9 +2861,9 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
255, 255, 255
);
- int currentNode = pBot->determineCurrentNodeWithTwoAttempts();
+ const int currentNode = pBot->determineCurrentNodeWithTwoAttempts();
if (currentNode > -1) {
- tNode *node = getNode(currentNode);
+ const tNode *node = getNode(currentNode);
// close node
DrawBeam(
@@ -2851,7 +2881,7 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
}
}
}
- } // Draw waypoint beams
+ }*/ // Draw waypoint beams
// reached node
if (bNearNode) {
@@ -2862,7 +2892,7 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
// TODO TODO TODO Water Navigation
- int nextNodeToHeadFor = pBot->getNextPathNode(); // the node we will head for after reaching currentNode
+ const int nextNodeToHeadFor = pBot->getNextPathNode(); // the node we will head for after reaching currentNode
// NO ENEMY, CHECK AROUND AREA
// This determines where to look at, no enemy == look at next node
@@ -2884,7 +2914,7 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
!isEntityWorldspawn(pEntityHit)) // and it is not worldspawn (ie, the map itself)
{
char msg[255];
- sprintf(msg, "Entity [%s] between me and next node.", STRING(pEntityHit->v.classname));
+ snprintf(msg, sizeof(msg), "Entity [%s] between me and next node.", STRING(pEntityHit->v.classname));
pBot->rprint_trace("cNodeMachine::path_walk", msg);
// hit by a door?
@@ -2901,10 +2931,14 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
return;
}
- if (strcmp(STRING(pEntityHit->v.classname), "player") == 0) {
+ if (std::strcmp(STRING(pEntityHit->v.classname), "player") == 0) {
pBot->rprint_trace("cNodeMachine::path_walk", "Another player between me and next node.");
- pBot->strafeRight(0.2);
- return;
+ if (pBot->hasTimeToMoveToNode()) {
+ pBot->strafeRight(0.2f);
+ pBot->rprint_trace("cNodeMachine::path_walk", "Time left to move to node, so lets try strafing to unstuck.");
+ return;
+ }
+ pBot->rprint_trace("cNodeMachine::path_walk", "No time left to move to node, so we continue and let stuck logic kick in");
}
pBot->rprint_trace("cNodeMachine::path_walk", "Finished - entity hit end block");
@@ -2915,24 +2949,27 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
// - unstuck
// - go back in path...
- float timeEvaluatingMoveSpeed = 0.1;
- bool notStuckForAWhile = (pBot->fNotStuckTime + timeEvaluatingMoveSpeed) < gpGlobals->time;
+ constexpr float timeEvaluatingMoveSpeed = 0.1f;
+ const bool notStuckForAWhile = pBot->fNotStuckTime + timeEvaluatingMoveSpeed < gpGlobals->time;
+
+ constexpr double fraction = 0.7; // 0.7 is an arbitrary number based on several tests to consider stuck at a more sane moment.
+ // Else it would trigger stuck logic too soon, too often.
- double fraction = 0.7; // 0.7 is an arbitrary number based on several tests to consider stuck at a more sane moment. Else it would trigger stuck logic too soon, too often.
- double speedInOneTenthOfASecond = (pBot->f_move_speed * timeEvaluatingMoveSpeed) * fraction;
+ const double speedInOneTenthOfASecond = static_cast(pBot->f_move_speed * timeEvaluatingMoveSpeed) * fraction;
double expectedMoveDistance = speedInOneTenthOfASecond;
if (pBot->isFreezeTime()) expectedMoveDistance = 0;
+ if (pBot->isWalking()) expectedMoveDistance = speedInOneTenthOfASecond / 3.0;
if (pBot->isDucking()) expectedMoveDistance = speedInOneTenthOfASecond / 3.0;
if (pBot->isJumping()) expectedMoveDistance = speedInOneTenthOfASecond / 3.0;
// no need for 'is walking' because walking time influence `f_move_speed` hence it is already taken care of
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Distance moved %f, expected %f, should be able to move yes, notStuck for a while %d", distanceMoved, expectedMoveDistance, notStuckForAWhile);
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "Distance moved %f, expected %f, should be able to move yes, notStuck for a while %d", distanceMoved,
+ expectedMoveDistance, notStuckForAWhile);
pBot->rprint_trace("cNodeMachine::path_walk", msg);
- bool isStuck = distanceMoved < expectedMoveDistance && pBot->shouldBeAbleToMove() && notStuckForAWhile; // also did not evaluate this logic for 0.5 second
- Vector &vector = Nodes[currentNodeToHeadFor].origin;
+ const bool isStuck = distanceMoved < expectedMoveDistance && pBot->shouldBeAbleToMove() && notStuckForAWhile; // also did not evaluate this logic for 0.5 second
+ const Vector &vector = Nodes[currentNodeToHeadFor].origin;
if (isStuck) {
pBot->rprint_trace("cNodeMachine::path_walk", "!!!STUCK STUCK STUCK STUCK STUCK STUCK STUCK!!!");
@@ -2944,8 +2981,8 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
if (pBot->getMoveToNodeTimeRemaining() < 0) {
pBot->rprint_trace("cNodeMachine::path_walk/timeRemaining", "Time is up!");
- int iFrom = pBot->getPreviousPathNodeToHeadFor();
- int iTo = currentNodeToHeadFor;
+ const int iFrom = pBot->getPreviousPathNodeToHeadFor();
+ const int iTo = currentNodeToHeadFor;
IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded(iFrom, iTo);
@@ -2957,71 +2994,81 @@ void cNodeMachine::path_walk(cBot *pBot, float distanceMoved) {
pBot->rprint_trace("cNodeMachine::path_walk", "Finished - really the end of the method");
}
-void cNodeMachine::ExecuteIsStuckLogic(cBot *pBot, int currentNodeToHeadFor, Vector &vector) {
+void cNodeMachine::ExecuteIsStuckLogic(cBot *pBot, const int currentNodeToHeadFor, const Vector& vector) {
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "START");
- pBot->fNotStuckTime = gpGlobals->time + 0.25; // give some time to unstuck
+ pBot->fNotStuckTime = gpGlobals->time + 0.25f; // give some time to unstuck
- int iFrom = pBot->getPreviousPathNodeToHeadFor();
- int iTo = currentNodeToHeadFor;
+ const int iFrom = pBot->getPreviousPathNodeToHeadFor();
+ const int iTo = currentNodeToHeadFor;
- // JUMP & DUCK
- tNode ¤tNode = Nodes[currentNodeToHeadFor];
- if (BotShouldJumpIfStuck(pBot) || (currentNode.iNodeBits & BIT_JUMP)) {
- pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Duck-jump tries increased, increase node time - START");
+ // JUMP & DUCK // TODO: Add a proper and reliable DuckJump Node [APG]RoboCop[CL]
+ const tNode ¤tNode = Nodes[currentNodeToHeadFor];
+ if (BotShouldJumpIfStuck(pBot) || currentNode.iNodeBits & BIT_JUMP) {
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Jump tries increased, increase node time - START");
pBot->doJump(vector);
pBot->iJumpTries++;
- pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Duck-jump tries increased, increase node time - END");
- pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Finished!");
- return;
- } else if (BotShouldDuck(pBot) || (currentNode.iNodeBits & BIT_DUCK)) {
- pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Duck tries increased, increase node time - START");
- pBot->doDuck();
- pBot->iDuckTries++;
- pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Duck tries increased, increase node time - END");
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Jump tries increased, increase node time - END");
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Finished!");
return;
- } else if (pBot->isOnLadder()) {
- pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Is stuck on ladder, trying to get of the ladder by jumping");
- pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Duck-jump tries increased");
- pBot->doJump(vector);
- pBot->iJumpTries++;
+ }
+ if (BotShouldDuck(pBot) || currentNode.iNodeBits & BIT_DUCK) {
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Duck tries increased, increase node time - START");
+ pBot->doDuck();
+ pBot->iDuckTries++;
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Duck tries increased, increase node time - END");
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Finished!");
+ return;
+ }
+ if (BotShouldDuckJump(pBot) || currentNode.iNodeBits & BIT_DUCKJUMP) {
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "DuckJump tries increased, increase node time - START");
+ pBot->doDuckJump();
+ pBot->iDuckJumpTries++;
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "DuckJump tries increased, increase node time - END");
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Finished!");
return;
}
+ if (pBot->isOnLadder()) {
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Is stuck on ladder, trying to get of the ladder by jumping");
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "DuckJump tries increased");
+ pBot->doJump(vector);
+ pBot->iJumpTries++;
+ pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Finished!");
+ return;
+ }
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "No need to duck or to jump");
- char msg[255];
- memset(msg, 0, sizeof(msg));
- float timeRemaining = pBot->getMoveToNodeTimeRemaining();
- sprintf(msg, "I still have %f seconds to go to node before considered 'stuck' for connection", timeRemaining);
+ char msg[255] = {};
+ const float timeRemaining = pBot->getMoveToNodeTimeRemaining();
+ snprintf(msg, sizeof(msg), "I still have %f seconds to go to node before considered 'stuck' for connection", timeRemaining);
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", msg);
- cBot *pBotStuck = getCloseFellowBot(pBot);
+ const cBot *pBotStuck = getCloseFellowBot(pBot);
// edict_t *playerNearbyInFOV = getPlayerNearbyBotInFOV(pBot);
edict_t *entityNearbyInFOV = getEntityNearbyBotInFOV(pBot);
- edict_t *playerNearbyInFOV = NULL;
- edict_t *hostageNearbyInFOV = NULL;
+ const edict_t *playerNearbyInFOV = nullptr;
+ edict_t *hostageNearbyInFOV = nullptr;
if (entityNearbyInFOV) {
- if (strcmp(STRING(entityNearbyInFOV->v.classname), "player") == 0) {
+ if (std::strcmp(STRING(entityNearbyInFOV->v.classname), "player") == 0) {
playerNearbyInFOV = entityNearbyInFOV;
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "A player is in front of me");
}
- if (strcmp(STRING(entityNearbyInFOV->v.classname), "hostage_entity") == 0) {
+ if (std::strcmp(STRING(entityNearbyInFOV->v.classname), "hostage_entity") == 0) {
hostageNearbyInFOV = entityNearbyInFOV;
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "A hostage is in front of me");
}
}
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Player in FOV? %d, hostage in FOV? %d bot close ? %d, time remaining? %f", playerNearbyInFOV != NULL, hostageNearbyInFOV != NULL, pBotStuck != NULL, timeRemaining);
+ std::memset(msg, 0, sizeof(msg));
+ snprintf(msg, sizeof(msg), "Player in FOV? %d, hostage in FOV? %d bot close ? %d, time remaining? %f",
+ playerNearbyInFOV != nullptr, hostageNearbyInFOV != nullptr, pBotStuck != nullptr, timeRemaining);
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", msg);
if (playerNearbyInFOV) {
- if (pBotStuck != NULL) {
+ if (pBotStuck != nullptr) {
if (pBotStuck->pEdict == playerNearbyInFOV) {
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "The player nearby in FOV is the close bot as well: it is a fellow bot that blocks me");
} else {
@@ -3063,13 +3110,13 @@ void cNodeMachine::ExecuteIsStuckLogic(cBot *pBot, int currentNodeToHeadFor, Vec
// should move, but no nearby bot found that could cause us to get stuck
// - when no players are close (could be blocked by them, do not learn stupid things)
- if (pBotStuck == NULL) {
+ if (pBotStuck == nullptr) {
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "There is no other BOT around making me go stuck");
// check if the connection we want is going up
// - when going up
// - when we should move
- bool nodeToHeadForIsHigher = currentNode.origin.z > pBot->pEdict->v.origin.z;
+ const bool nodeToHeadForIsHigher = currentNode.origin.z > pBot->pEdict->v.origin.z;
if (nodeToHeadForIsHigher) {
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "Node to head for is higher than me");
// check if the next node is floating (skip self)
@@ -3087,7 +3134,7 @@ void cNodeMachine::ExecuteIsStuckLogic(cBot *pBot, int currentNodeToHeadFor, Vec
// make sure we head to the current node
pBot->vBody = currentNode.origin;
pBot->vHead = currentNode.origin;
- pBot->fNotStuckTime = gpGlobals->time + 0.5; // give a bit more time
+ pBot->fNotStuckTime = gpGlobals->time + 0.5f; // give a bit more time
} else {
pBot->rprint_trace("cNodeMachine::ExecuteIsStuckLogic", "I can no longer see the current node to head for");
IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded(iFrom, iTo);
@@ -3117,10 +3164,10 @@ void cNodeMachine::ExecuteIsStuckLogic(cBot *pBot, int currentNodeToHeadFor, Vec
void cNodeMachine::ExecuteNearNodeLogic(cBot *pBot) {
pBot->rprint_trace("cNodeMachine::ExecuteNearNodeLogic", "Start");
- int currentNodeToHeadFor = pBot->getCurrentPathNodeToHeadFor();
+ const int currentNodeToHeadFor = pBot->getCurrentPathNodeToHeadFor();
// first determine if we where heading for a goal node
- bool isHeadingForGoalNode = pBot->isHeadingForGoalNode();
+ const bool isHeadingForGoalNode = pBot->isHeadingForGoalNode();
// increase index on path, so we will go to next node
pBot->nextPathIndex();
@@ -3133,21 +3180,20 @@ void cNodeMachine::ExecuteNearNodeLogic(cBot *pBot) {
if (!isHeadingForGoalNode) {
- char msg[255];
- memset(msg, 0, sizeof(msg));
+ char msg[255] = {};
- int currentPathNode = pBot->getCurrentPathNodeToHeadFor();
+ const int currentPathNode = pBot->getCurrentPathNodeToHeadFor();
if (currentPathNode > -1) {
- int troubleIndex = GetTroubleIndexForConnection(pBot->getPreviousPathNodeToHeadFor(), currentNodeToHeadFor);
+ const int troubleIndex = GetTroubleIndexForConnection(pBot->getPreviousPathNodeToHeadFor(), currentNodeToHeadFor);
if (troubleIndex > -1) {
- tTrouble &trouble = Troubles[troubleIndex];
- sprintf(msg, "Heading to next node: %d, trouble (tries) %d", currentPathNode, trouble.iTries);
+ const tTrouble &trouble = Troubles[troubleIndex];
+ snprintf(msg, sizeof(msg), "Heading to next node: %d, trouble (tries) %d", currentPathNode, trouble.iTries);
} else {
- sprintf(msg, "Heading to next node: %d - with no trouble", currentPathNode);
+ snprintf(msg, sizeof(msg), "Heading to next node: %d - with no trouble", currentPathNode);
}
} else {
- sprintf(msg, "Heading to next node: %d", currentPathNode);
+ snprintf(msg, sizeof(msg), "Heading to next node: %d", currentPathNode);
}
pBot->rprint("cNodeMachine::path_walk()", msg);
}
@@ -3199,7 +3245,7 @@ void cNodeMachine::ExecuteNearNodeLogic(cBot *pBot) {
// At destination, bomb is planted and we have not discovered the C4 yet...
// TODO: Remember which goals/bomb spots have been visited so bots won't visit this bomb spot again?
- int iGoalType = getGoalIndexFromNode(pBot->getGoalNode());
+ const int iGoalType = getGoalIndexFromNode(pBot->getGoalNode());
if (pBot->isCounterTerrorist()) {
if (Game.bBombPlanted && !Game.isPlantedC4Discovered()) {
@@ -3228,32 +3274,36 @@ void cNodeMachine::ExecuteNearNodeLogic(cBot *pBot) {
* @param pEntityHit
* @return
*/
-bool cNodeMachine::isDoorThatOpensWhenPressingUseButton(const edict_t *pEntityHit) const {
+bool cNodeMachine::isDoorThatOpensWhenPressingUseButton(const edict_t *pEntityHit)
+{
return FBitSet(pEntityHit->v.spawnflags, SF_DOOR_USE_ONLY) &&
!(FBitSet(pEntityHit->v.spawnflags, SF_DOOR_NO_AUTO_RETURN));
}
-bool cNodeMachine::isEntityDoor(const edict_t *pEntityHit) const {
- return strcmp(STRING(pEntityHit->v.classname), "func_door") == 0 || // normal door (can be used as an elevator)
- strcmp(STRING(pEntityHit->v.classname), "func_wall") == 0 || // I am not 100% sure about func_wall, but include it anyway
- strcmp(STRING(pEntityHit->v.classname), "func_door_rotating") == 0; // rotating door
+bool cNodeMachine::isEntityDoor(const edict_t *pEntityHit)
+{
+ return std::strcmp(STRING(pEntityHit->v.classname), "func_door") == 0 || // normal door (can be used as an elevator)
+ std::strcmp(STRING(pEntityHit->v.classname), "func_wall") == 0 || // I am not 100% sure about func_wall, but include it anyway
+ std::strcmp(STRING(pEntityHit->v.classname), "func_door_rotating") == 0; // rotating door
}
-bool cNodeMachine::isEntityHostage(const edict_t *pEntityHit) const {
- return strcmp(STRING(pEntityHit->v.classname), "hostage_entity") == 0; // hostage
+bool cNodeMachine::isEntityHostage(const edict_t *pEntityHit)
+{
+ return std::strcmp(STRING(pEntityHit->v.classname), "hostage_entity") == 0; // hostage
}
-bool cNodeMachine::isEntityWorldspawn(const edict_t *pEntityHit) const {
- return strcmp(STRING(pEntityHit->v.classname), "worldspawn") == 0; // the world
+bool cNodeMachine::isEntityWorldspawn(const edict_t *pEntityHit)
+{
+ return std::strcmp(STRING(pEntityHit->v.classname), "worldspawn") == 0; // the world
}
// Think about path creation here
-void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
+void cNodeMachine::path_think(cBot *pBot, const float distanceMoved) {
pBot->rprint_trace("cNodeMachine::path_think", "START");
if (pBot->shouldBeWandering()) {
int currentNode = -1;
for (int attempts = 1; attempts < 5; attempts++) {
- float distance = NODE_ZONE + (attempts * NODE_ZONE);
+ const float distance = static_cast(NODE_ZONE) + static_cast(attempts * NODE_ZONE);
currentNode = pBot->determineCurrentNode(distance); // this also sets current node in bot state
if (currentNode > -1) break;
}
@@ -3270,9 +3320,8 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
if (pBot->canSeeHostageToRescue()) {
pBot->rprint_trace("cNodeMachine::path_think", "has hostage and can see hostage, will not do anything");
return; // bot has hostage, can see hostage
- } else {
- pBot->rprint_trace("cNodeMachine::path_think", "has hostage to rescue, but can't see it");
}
+ pBot->rprint_trace("cNodeMachine::path_think", "has hostage to rescue, but can't see it");
}
if (pBot->shouldActWithC4()) {
@@ -3285,7 +3334,7 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
pBot->rprint("cNodeMachine::path_think", "Time to camp");
if (!pBot->hasGoal()) {
pBot->rprint("cNodeMachine::path_think", "Setting goal to look for camping");
- int noteToLookAt = node_look_camp(pBot->pEdict->v.origin, UTIL_GetTeam(pBot->pEdict), pBot->pEdict);
+ const int noteToLookAt = node_look_camp(pBot->pEdict->v.origin, UTIL_GetTeam(pBot->pEdict), pBot->pEdict);
pBot->setGoalNode(noteToLookAt);
}
return;
@@ -3306,14 +3355,14 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
pBot->rprint_trace("cNodeMachine::path_think", "I am not walking a path.");
- int thisBotIndex = pBot->iBotIndex;
+ const int thisBotIndex = pBot->iBotIndex;
// No path
pBot->stopMoving();
if (pBot->hasGoal()) {
// there is no path, but there is a goal to work to
- int iCurrentNode = pBot->determineCurrentNodeWithTwoAttempts();
+ const int iCurrentNode = pBot->determineCurrentNodeWithTwoAttempts();
if (iCurrentNode < 0) {
pBot->forgetGoal();
@@ -3354,40 +3403,36 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
// DETERMINE GOAL / FIND GOAL
// Loop through all goals.
- float highestScore = 0.0;
+ float highestScore = 0.0f;
int iFinalGoalNode = -1;
int iFinalGoalIndex = -1;
- int goalIndex = 0;
-
- float MAX_DISTANCE = 16384.0; // theoretical max distance
- float MAX_GOAL_DISTANCE = MAX_DISTANCE / 2.0;
+ constexpr float MAX_DISTANCE = 16384.0f; // theoretical max distance
+ constexpr float MAX_GOAL_DISTANCE = MAX_DISTANCE / 2.0f;
// 01-07-2008; Instead of using 'scores', use a normalized score.
// We do:
// (current score + gained score) / 2.0;
// Since both scores can be max 1.0, meaning we keep it between 0.0 and 1.0
// A score of 1.0 is max.
- int maxCheckedScore = 5;
pBot->rprint_normal("cNodeMachine::path_think", "going to choose goal");
- for (goalIndex = 0; goalIndex < MAX_GOALS; goalIndex++) {
+ for (int goalIndex = 0; goalIndex < MAX_GOALS; ++goalIndex) {
+ constexpr int maxCheckedScore = 5;
- // Make sure this goal is valid
+ // Make sure this goal is valid
if (Goals[goalIndex].iNode < 0) {
continue;
}
- float score = 0.0f; // start with 0
-
- float fDistanceToGoal = func_distance(
+ const float fDistanceToGoal = func_distance(
pBot->pEdict->v.origin,
node_vector(Goals[goalIndex].iNode)
);
// First score is distance, so just set it:
- score = fDistanceToGoal / MAX_GOAL_DISTANCE;
+ float score = fDistanceToGoal / MAX_GOAL_DISTANCE;
if (Goals[goalIndex].iChecked > maxCheckedScore) {
// it has been very popular, reset
@@ -3395,30 +3440,30 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
}
// A bit off randomness
- float weight = 50 / pBot->ipRandom; // (yes, this will give us 1 or higher score)
+ float weight = 50.0f / static_cast(pBot->ipRandom); // (yes, this will give us 1 or higher score)
weight *= score;
score += weight;
// Take into consideration how many times this goal has been selected
- score = (score + (1.0f - (Goals[goalIndex].iChecked / maxCheckedScore))) / 2.0f;
+ score = (score + (1.0f - static_cast(Goals[goalIndex].iChecked) / static_cast(maxCheckedScore))) / 2.0f;
// Danger (is important)
- score = (score + InfoNodes[Goals[goalIndex].iNode].fDanger[UTIL_GetTeam(pBot->pEdict)]) / 1.5;
+ score = (score + InfoNodes[Goals[goalIndex].iNode].fDanger[UTIL_GetTeam(pBot->pEdict)]) / 1.5f;
// How many bots have already taken this goal?
- float goalAlreadyUsedScore = 0.0;
- float teamMembers = 1.0; // count self by default
-
- for (int botIndex = 0; botIndex < MAX_BOTS; botIndex++) {
+ float goalAlreadyUsedScore = 0.0f;
+ float teamMembers = 1.0f; // count self by default
+
+ for (cBot& bot : bots)
+ {
// not a bot
- cBot *botPointer = &bots[botIndex];
- if (botPointer == NULL ||
- !botPointer->bIsUsed ||
+ const cBot* botPointer = ⊥
+ if (!botPointer->bIsUsed ||
botPointer == pBot) { // skip self
continue;
}
-
+
// real bots..
if (pBot->isOnSameTeamAs(botPointer)) {
teamMembers++;
@@ -3429,14 +3474,14 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
}
// add favoriteness
- score = (score + (1.0 - (goalAlreadyUsedScore / teamMembers))) / 2.0;
+ score = (score + (1.0f - goalAlreadyUsedScore / teamMembers)) / 2.0f;
// Goals regardless of map/game type
- int goalType = Goals[goalIndex].iType;
+ const int goalType = Goals[goalIndex].iType;
if (goalType == GOAL_SPAWNCT || goalType == GOAL_SPAWNT) {
- float goalscore = fDistanceToGoal / MAX_GOAL_DISTANCE;
- score = (score + goalscore) / 2.0;
+ const float goalscore = fDistanceToGoal / MAX_GOAL_DISTANCE;
+ score = (score + goalscore) / 2.0f;
}
if (Game.bHostageRescueMap) {
@@ -3446,87 +3491,91 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
if (pBot->isEscortingHostages()) {
pBot->rprint("I am escorting hostages - assuming ct spawn is rescue zone and prioritizing");
// highest priority
- score = 2.0;
+ score = 2.0f;
}
}
}
if (goalType == GOAL_HOSTAGE) {
- // counter-terrorist should
- float goalscore = 0.0;
+ float goalscore = 0.0f;
+
+ // Counter-Terrorist hostage rescue logic
if (pBot->isCounterTerrorist()) {
if (pBot->isEscortingHostages()) {
pBot->rprint("I am escorting hostages - should ignore existing hostages");
- // already escorting hostages, low interest for other hostages
- goalscore = 0.5;
- } else {
- // always go to the most furthest hostage spot, and add some randomness here, else
- // all bots go to there.
- float mul = MAX_GOAL_DISTANCE / fDistanceToGoal;
- goalscore = 1 + mul;
+ // Already escorting hostages, low interest for other hostages
+ goalscore = 0.5f;
}
- } else {
- // Terrorist pick randomly this location
+ else {
+ // Prioritize closer hostages for a quicker rescue.
+ // The score is inversely proportional to the distance.
+ // Adding a small random factor to prevent all bots picking the same hostage.
+ goalscore = (MAX_GOAL_DISTANCE / std::max(fDistanceToGoal, 1.0f)) + RANDOM_FLOAT(0.1f, 0.2f);
+ }
+ }
+ // Terrorist logic for hostage locations
+ else {
+ // Terrorists have a low chance to guard a hostage location.
if (RANDOM_LONG(0, 100) < 25) {
- goalscore = RANDOM_FLOAT(0.1, 0.6);
+ goalscore = RANDOM_FLOAT(0.1f, 0.6f);
}
}
- score = (score + goalscore) / 2.0;
- } else if (goalType == GOAL_RESCUEZONE) {
+ score = (score + goalscore) / 2.0f;
+ }
+ else if (goalType == GOAL_RESCUEZONE) {
if (pBot->isCounterTerrorist()) {
if (pBot->isEscortingHostages()) {
pBot->rprint("I am escorting hostages - prioritizing for rescue zone");
// highest priority
- score = 2.0;
+ score = 2.0f;
} else {
- score = 0.2;
+ score = 0.2f;
}
} else if (pBot->isTerrorist()) {
// TODO: when hostages are being rescued, go to a rescue zone to catch CT's and
// prevent rescue
- score = 0.2;
+ score = 0.2f;
}
}
} else { // it is a DE_ map
if (goalType == GOAL_BOMBSPOT) {
- float goalscore = 0.0;
+ float goalscore = 0.0f;
if (pBot->isTerrorist()) {
if (pBot->hasBomb()) {
- goalscore = 2.0; // plant it!
+ goalscore = 2.0f; // plant it!
} else {
- float mul = fDistanceToGoal / MAX_GOAL_DISTANCE;
- goalscore = (0.7 * mul);
+ const float mul = fDistanceToGoal / MAX_GOAL_DISTANCE;
+ goalscore = 0.7f * mul;
}
} else if (pBot->isCounterTerrorist()) {
if (Game.bBombPlanted) {
if (Game.isPlantedC4Discovered()) {
pBot->rprint_trace("path_think/determine goal", "I know where the C4 is planted, evaluating if this is the closest bombspot.");
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "C4 is located at %f, %f, %f", Game.vPlantedC4.x, Game.vPlantedC4.y, Game.vPlantedC4.z);
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "C4 is located at %f, %f, %f", Game.vPlantedC4.x, Game.vPlantedC4.y, Game.vPlantedC4.z);
pBot->rprint_trace("path_think/determine goal", msg);
// find a node close to the C4
- int nodeCloseToC4 = getClosestNode(Game.vPlantedC4, NODE_ZONE * 2, NULL);
+ const int nodeCloseToC4 = getClosestNode(Game.vPlantedC4, NODE_ZONE * 2, nullptr);
if (nodeCloseToC4 > -1) {
// measure distance compared to goal node we are evaluating
- float distanceToC4FromCloseNode = func_distance(
+ const float distanceToC4FromCloseNode = func_distance(
Game.vPlantedC4,
node_vector(Goals[nodeCloseToC4].iNode)
);
// the distance from this goal node
- float distanceToC4FromThisGoalNode = func_distance(
+ const float distanceToC4FromThisGoalNode = func_distance(
Game.vPlantedC4,
node_vector(Goals[goalIndex].iNode)
);
- float score = distanceToC4FromCloseNode / distanceToC4FromThisGoalNode;
- goalscore = 1.5 + score;
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Distance from C4 to closest node is %f, distance from evaluating node to C4 is %f, resulting into score of %f",
+ score = distanceToC4FromCloseNode / distanceToC4FromThisGoalNode;
+ goalscore = 1.5f + score;
+ std::memset(msg, 0, sizeof(msg));
+ snprintf(msg, sizeof(msg), "Distance from C4 to closest node is %f, distance from evaluating node to C4 is %f, resulting into score of %f",
distanceToC4FromCloseNode,
distanceToC4FromThisGoalNode,
goalscore);
@@ -3534,20 +3583,20 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
} else {
pBot->rprint_trace("path_think/determine goal", "We know where the C4 is planted, but unfortunately we can't find a close node to the planted c4.");
// we can't find a node close to the c4, so we gamble
- goalscore = 2.0; // pick
+ goalscore = 2.0f; // pick
}
} else {
pBot->rprint_trace("path_think/determine goal", "No clue where bomb is, picking bombspot to evaluate");
- goalscore = 2.0; // pick any bombspot
+ goalscore = 2.0f; // pick any bombspot
}
} else {
pBot->rprint_trace("path_think/determine goal", "Bomb is not planted");
- float mul = fDistanceToGoal / MAX_GOAL_DISTANCE;
- goalscore = (0.7 * mul);
+ const float mul = fDistanceToGoal / MAX_GOAL_DISTANCE;
+ goalscore = 0.7f * mul;
}
}
// this is weird? what?
- score = (score + goalscore) / 2.0;
+ score = (score + goalscore) / 2.0f;
} // GOAL is a bombspot
} // bomb plant map
@@ -3560,23 +3609,24 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
if (pBot->isCounterTerrorist()) {
if (pBot->vip) {
// VIP wants to get out
- score = 2.0;
+ score = 2.0f;
}
} else {
// terrorists pick random
- score = (score + RANDOM_FLOAT(0.0, 1.0)) / 2.0;
+ score = (score + RANDOM_FLOAT(0.0f, 1.0f)) / 2.0f;
}
}
-
+
if (goalType == GOAL_VIP) {
if (pBot->isCounterTerrorist()) {
if (pBot->vip) {
score = 0; // do not chase yourself
} else {
- // if distance is too big, go to it. (guard the VIP)
- int maxDistanceWeKeepToVIP = 500;
- float goalScore = maxDistanceWeKeepToVIP / fDistanceToGoal;
- score = (score + goalScore) / 2.0;
+ score = 0; // don't care about VIP
+ // if distance is too big, go to it. (guard the VIP)
+ constexpr int maxDistanceWeKeepToVIP = 500;
+ const float goalScore = maxDistanceWeKeepToVIP / fDistanceToGoal;
+ score = (score + goalScore) / 2.0f;
}
}
}
@@ -3585,7 +3635,7 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
{
// Maximum importance when acting as T
if (pBot->iTeam == 1) {
- score = 2.0;
+ score = 2.0f;
}
}
@@ -3604,7 +3654,7 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
// was previous goal as well, don't go there
if (pBot->iPreviousGoalNode == goalIndex) {
- score *= 0.2; // low chance
+ score *= 0.2f; // low chance
}
@@ -3614,14 +3664,11 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
// even though its float comparison, it can h appen since we hard-set it to 2.0 at some places, making
// some scores the same
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Evaluating goal %s gives a score of %f, highest score so far is %f",
- Goals[goalIndex].name,
- score,
- highestScore);
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "Evaluating goal %s gives a score of %f, highest score so far is %f",
+ Goals[goalIndex].name, score, highestScore);
pBot->rprint_trace("path_think/determine goal", msg);
- if (score == highestScore && RANDOM_LONG(0,100) < 50) {
+ if (static_cast(score) == static_cast(highestScore) && RANDOM_LONG(0,100) < 50) {
pBot->rprint_trace("path_think/determine goal", "SCORE == HIGHEST SCORE and chosen to override randomly.");
highestScore = score;
iFinalGoalNode = Goals[goalIndex].iNode;
@@ -3651,11 +3698,11 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
// Well it looks like we override the 'final' goal node (not so final after all huh?) to the dropped c4
if (Game.vDroppedC4 != Vector(9999, 9999, 9999) && // c4 dropped somewhere
- pBot->pButtonEdict == NULL) { // not using button
+ pBot->pButtonEdict == nullptr) { // not using button
// randomly, if we 'feel like picking up the bomb' just override the 'final' goal node
if (RANDOM_LONG(0, 100) < pBot->ipDroppedBomb) {
- iFinalGoalNode = getClosestNode(Game.vDroppedC4, 75, NULL);
+ iFinalGoalNode = getClosestNode(Game.vDroppedC4, 75, nullptr);
}
}
@@ -3685,11 +3732,10 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
pBot->setGoalNode(iFinalGoalNode, iFinalGoalIndex);
tGoal *goalData = pBot->getGoalData();
- char msg[255];
- memset(msg, 0, sizeof(msg));
+ char msg[255] = {};
- if (goalData != NULL) {
- sprintf(msg, "I have chosen a goal: Node [%d], Goal type [%s], checked [%d], score [%f], distance [%f]",
+ if (goalData != nullptr) {
+ snprintf(msg, sizeof(msg), "I have chosen a goal: Node [%d], Goal type [%s], checked [%d], score [%f], distance [%f]",
iFinalGoalNode,
goalData->name,
goalData->iChecked,
@@ -3697,7 +3743,7 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
pBot->getDistanceTo(iFinalGoalNode)
);
} else {
- sprintf(msg, "I have chosen a goal: Node [%d], - NO GOAL DATA - score [%f], distance [%f]",
+ snprintf(msg, sizeof(msg), "I have chosen a goal: Node [%d], - NO GOAL DATA - score [%f], distance [%f]",
iFinalGoalNode,
highestScore,
pBot->getDistanceTo(iFinalGoalNode)
@@ -3722,7 +3768,7 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
// }
// create path
- bool success = createPath(iCurrentNode, pBot->getGoalNode(), thisBotIndex, pBot, pBot->iPathFlags);
+ const bool success = createPath(iCurrentNode, pBot->getGoalNode(), thisBotIndex, pBot, pBot->iPathFlags);
// If we still did not find a path, we set wander time
// for 1 second we wait before a new attempt to find a goal and create a path.
@@ -3731,7 +3777,7 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
pBot->rprint("cNodeMachine::path_think()", "Finding node nearby to move to");
pBot->setGoalNode(getClosestNode(pBot->pEdict->v.origin, NODE_ZONE * 5, pBot->pEdict));
- bool successToAlternative = createPath(iCurrentNode, pBot->getGoalNode(), thisBotIndex, pBot, pBot->iPathFlags);
+ const bool successToAlternative = createPath(iCurrentNode, pBot->getGoalNode(), thisBotIndex, pBot, pBot->iPathFlags);
if (!successToAlternative) {
pBot->rprint("cNodeMachine::path_think()", "Unable to create path to node nearby.");
@@ -3741,64 +3787,48 @@ void cNodeMachine::path_think(cBot *pBot, float distanceMoved) {
}
}
-tNode *cNodeMachine::getNode(int index) {
+tNode *cNodeMachine::getNode(const int index) {
// safe-guard
- if (index < 0 || index >= MAX_NODES) return NULL;
+ if (index < 0 || index >= MAX_NODES) return nullptr;
return &Nodes[index];
}
-char *cNodeMachine::getGoalTypeAsText(const tGoal &goal) const {
- char typeAsText[32];
- memset(typeAsText, 0, sizeof(typeAsText));
-
+std::string cNodeMachine::getGoalTypeAsText(const tGoal& goal)
+{
switch (goal.iType) {
- case GOAL_SPAWNT:
- sprintf(typeAsText, "GOAL_SPAWNT");
- break;
- case GOAL_SPAWNCT:
- sprintf(typeAsText, "GOAL_SPAWNCT");
- break;
+ case GOAL_SPAWNT:
+ return "GOAL_SPAWNT";
+ case GOAL_SPAWNCT:
+ return "GOAL_SPAWNCT";
case GOAL_BOMBSPOT:
- sprintf(typeAsText, "GOAL_BOMBSPOT");
- break;
+ return "GOAL_BOMBSPOT";
case GOAL_BOMB:
- sprintf(typeAsText, "GOAL_BOMB");
- break;
+ return "GOAL_BOMB";
case GOAL_HOSTAGE:
- sprintf(typeAsText, "GOAL_HOSTAGE");
- break;
+ return "GOAL_HOSTAGE";
case GOAL_RESCUEZONE:
- sprintf(typeAsText, "GOAL_RESCUEZONE");
- break;
+ return "GOAL_RESCUEZONE";
case GOAL_CONTACT:
- sprintf(typeAsText, "GOAL_CONTACT");
- break;
+ return "GOAL_CONTACT";
case GOAL_IMPORTANT:
- sprintf(typeAsText, "GOAL_IMPORTANT");
- break;
+ return "GOAL_IMPORTANT";
case GOAL_VIP:
- sprintf(typeAsText, "GOAL_VIP");
- break;
+ return "GOAL_VIP";
case GOAL_VIPSAFETY:
- sprintf(typeAsText, "GOAL_VIPSAFETY");
- break;
+ return "GOAL_VIPSAFETY";
case GOAL_ESCAPEZONE:
- sprintf(typeAsText, "GOAL_ESCAPEZONE");
- break;
+ return "GOAL_ESCAPEZONE";
case GOAL_WEAPON:
- sprintf(typeAsText, "GOAL_WEAPON");
- break;
+ return "GOAL_WEAPON";
case GOAL_NONE:
- sprintf(typeAsText, "GOAL_NONE");
- break;
+ return "GOAL_NONE";
default:
- sprintf(typeAsText, "GOAL UNKNOWN");
+ return "GOAL UNKNOWN";
}
- return typeAsText;
}
// Find cover
-int cNodeMachine::node_cover(int iFrom, int iTo, edict_t *pEdict) {
+int cNodeMachine::node_cover(const int iFrom, const int iTo, edict_t *pEdict) {
if (iFrom == iTo)
return iFrom; // cover at current position
@@ -3822,14 +3852,14 @@ int cNodeMachine::node_cover(int iFrom, int iTo, edict_t *pEdict) {
// is no option.
// Note: this function is only called once for finding some node to take cover from
- // Most bad situation would be that 31 bots call this function in 1 frame.
+ // Most bad scenario would be that 31 bots call this function in 1 frame.
// TEMP sollution:
float fClosest = 512;
int iClosest = -1;
for (int i = 0; i < MAX_NODES; i++)
- if ((i != iTo) && (Nodes[i].origin != Vector(9999, 9999, 9999))) {
- float fDistance =
+ if (i != iTo && Nodes[i].origin != Vector(9999, 9999, 9999)) {
+ const float fDistance =
func_distance(Nodes[i].origin, Nodes[iFrom].origin);
if (fDistance < fClosest) {
// all nodes within this range may be tracelined
@@ -3841,13 +3871,26 @@ int cNodeMachine::node_cover(int iFrom, int iTo, edict_t *pEdict) {
UTIL_TraceLine(Nodes[iFrom].origin, Nodes[i].origin,
ignore_monsters, ignore_glass, pEdict, &tr);
- if (tr.flFraction < 1.0)
+ if (tr.flFraction < 1.0f)
bVisible = false;
- } else {
- if (GetVisibilityFromTo(iFrom, i) == VIS_BLOCKED) // BERKED
+ }
+
+ if (GetVisibilityFromTo(i, iFrom) == VIS_UNKNOWN) // BERKED
+ {
+ UTIL_TraceLine(Nodes[i].origin, Nodes[iFrom].origin,
+ ignore_monsters, ignore_glass, pEdict, &tr);
+
+ if (tr.flFraction < 1.0f)
bVisible = false;
}
+ // only when really blocked, count it as false.
+ if (GetVisibilityFromTo(iFrom, i) == VIS_BLOCKED)
+ bVisible = false;
+
+ if (GetVisibilityFromTo(i, iFrom) == VIS_BLOCKED)
+ bVisible = false;
+
// Hit something
if (bVisible == false) {
// Update VisTable
@@ -3866,8 +3909,7 @@ int cNodeMachine::node_cover(int iFrom, int iTo, edict_t *pEdict) {
}
-int cNodeMachine::node_look_at_hear(int iFrom, int iOrigin,
- edict_t *pEdict) {
+int cNodeMachine::node_look_at_hear(const int iFrom, const int iOrigin, edict_t *pEdict) {
if (iFrom == iOrigin)
return iFrom; // impossible
@@ -3892,8 +3934,8 @@ int cNodeMachine::node_look_at_hear(int iFrom, int iOrigin,
// we search for a node that can see the sound node (iFrom) and the origin node (iOrigin)
for (int i = 0; i < MAX_NODES; i++)
- if ((i != iOrigin && i != iFrom)
- && (Nodes[i].origin != Vector(9999, 9999, 9999))) {
+ if (i != iOrigin && i != iFrom
+ && Nodes[i].origin != Vector(9999, 9999, 9999)) {
if (func_distance(Nodes[i].origin, Nodes[iOrigin].origin) >
BOT_HEARDISTANCE)
continue;
@@ -3909,7 +3951,7 @@ int cNodeMachine::node_look_at_hear(int iFrom, int iOrigin,
UTIL_TraceLine(Nodes[iFrom].origin, Nodes[i].origin,
ignore_monsters, ignore_glass, pEdict, &tr);
- if (tr.flFraction < 1.0) {
+ if (tr.flFraction < 1.0f) {
SetVisibilityFromTo(iFrom, i, false);
SetVisibilityFromTo(i, iFrom, false);
}
@@ -3920,7 +3962,7 @@ int cNodeMachine::node_look_at_hear(int iFrom, int iOrigin,
UTIL_TraceLine(Nodes[iOrigin].origin, Nodes[i].origin,
ignore_monsters, ignore_glass, pEdict, &tr);
- if (tr.flFraction < 1.0) {
+ if (tr.flFraction < 1.0f) {
SetVisibilityFromTo(iOrigin, i, false);
SetVisibilityFromTo(i, iOrigin, false);
}
@@ -3943,147 +3985,133 @@ int cNodeMachine::node_look_at_hear(int iFrom, int iOrigin,
return iClosest;
}
-void cNodeMachine::dump_goals(void) {
- int i;
- char buffer[100];
- Vector v;
-
- rblog("Dump of all goals\n");
- for (i = 0; (i < MAX_GOALS) && (Goals[i].iNode >= 0); i++) {
- v = Nodes[Goals[i].iNode].origin;
- sprintf(buffer,
- "Goal#%d is at node %d (%.0f, %.0f, %.0f), iChecked= %d, ",
- i + 1, Goals[i].iNode, v.x, v.y, v.z, Goals[i].iChecked);
+void cNodeMachine::dump_goals() const
+{
+ rblog("Dump of all goals\n");
+ for (int i = 0; i < MAX_GOALS && Goals[i].iNode >= 0; i++) {
+ char buffer[100];
+ const Vector v = Nodes[Goals[i].iNode].origin;
+ snprintf(buffer, sizeof(buffer),
+ "Goal#%d is at node %d (%.0f, %.0f, %.0f), iChecked= %d, ",
+ i + 1, Goals[i].iNode, v.x, v.y, v.z, Goals[i].iChecked);
switch (Goals[i].iType) {
case GOAL_SPAWNCT:
- strcat(buffer, "GOAL_SPAWNCT");
+ std::strcat(buffer, "GOAL_SPAWNCT");
break;
case GOAL_SPAWNT:
- strcat(buffer, "GOAL_SPAWNT");
+ std::strcat(buffer, "GOAL_SPAWNT");
break;
case GOAL_BOMBSPOT:
- strcat(buffer, "GOAL_BOMBSPOT");
+ std::strcat(buffer, "GOAL_BOMBSPOT");
break;
case GOAL_BOMB:
- strcat(buffer, "GOAL_BOMB");
+ std::strcat(buffer, "GOAL_BOMB");
break;
case GOAL_HOSTAGE:
- strcat(buffer, "GOAL_HOSTAGE");
+ std::strcat(buffer, "GOAL_HOSTAGE");
break;
case GOAL_RESCUEZONE:
- strcat(buffer, "GOAL_RESCUEZONE");
+ std::strcat(buffer, "GOAL_RESCUEZONE");
break;
case GOAL_CONTACT:
- strcat(buffer, "GOAL_CONTACT");
+ std::strcat(buffer, "GOAL_CONTACT");
break;
case GOAL_IMPORTANT:
- strcat(buffer, "GOAL_IMPORTANT");
+ std::strcat(buffer, "GOAL_IMPORTANT");
break;
case GOAL_VIP:
- strcat(buffer, "GOAL_VIP");
+ std::strcat(buffer, "GOAL_VIP");
break;
case GOAL_VIPSAFETY:
- strcat(buffer, "GOAL_VIPSAFETY");
+ std::strcat(buffer, "GOAL_VIPSAFETY");
break;
case GOAL_ESCAPEZONE:
- strcat(buffer, "GOAL_ESCAPEZONE");
+ std::strcat(buffer, "GOAL_ESCAPEZONE");
break;
case GOAL_WEAPON:
- strcat(buffer, "GOAL_WEAPON");
+ std::strcat(buffer, "GOAL_WEAPON");
break;
case GOAL_NONE:
- strcat(buffer, "GOAL_NONE");
+ std::strcat(buffer, "GOAL_NONE");
break;
default:
- strcat(buffer, "unknown type");
+ std::strcat(buffer, "unknown type");
}
- strcat(buffer, "\n");
+ std::strcat(buffer, "\n");
rblog(buffer);
}
}
// EVY: another dump
-void cNodeMachine::dump_path(int iBot, int CurrentPath) {
- char buffer[80];
- int i, j, CurrentNode;
- Vector v;
-
- if (CurrentPath >= 0)
- CurrentNode = iPath[iBot][CurrentPath];
- else
- CurrentNode = -1;
- rblog(" Path is: ");
- for (i = 0; (i < MAX_NODES) && (iPath[iBot][i] >= 0); i++) {
- if (i == CurrentPath)
- sprintf(buffer, "<%d> ", iPath[iBot][i]);
- else
- sprintf(buffer, "%d ", iPath[iBot][i]);
- rblog(buffer);
- }
- rblog("\n");
- if (CurrentNode < 0)
- return;
- rblog(" Current direct neighbours are:\n");
- for (i = 0; i < MAX_NEIGHBOURS; i++)
- if (Nodes[CurrentNode].iNeighbour[i] >= 0) {
- j = Nodes[CurrentNode].iNeighbour[i];
- v = Nodes[j].origin;
- sprintf(buffer, " %d (%.0f, %.0f, %.0f)\n", j, v.x, v.y,
- v.z);
+void cNodeMachine::dump_path(const int iBot, const int CurrentPath) const
+{
+ char buffer[181];
+ snprintf(buffer, 180, " Path for bot %d (current index %d): ", iBot, CurrentPath);
+ rblog(buffer);
+
+ bool path_exists = false;
+ for (int i = 0; i < MAX_PATH_NODES; ++i) {
+ int node_index = iPath[iBot][i];
+ if (node_index != -1) {
+ path_exists = true;
+ snprintf(buffer, 180, "%d ", node_index);
rblog(buffer);
}
- rblog("\n");
+ else {
+ break; // End of path
+ }
+ }
+
+ if (!path_exists) {
+ rblog("No path.\n");
+ }
+ else {
+ rblog("\n");
+ }
}
// EVY a lot of things to draw: nodes, neighbours, goals, paths, ...
// Graphs from PMB & Botman
// width and height of the debug bitmap image
-#define DEBUG_BMP_WIDTH 2048
-#define DEBUG_BMP_HEIGHT 2048
+enum : std::uint16_t
+{
+ DEBUG_BMP_WIDTH = 2048,
+ DEBUG_BMP_HEIGHT = 2048
+};
-static char *bmp_buffer;
+static std::vector bmp_buffer;
static float maxx, maxy, minx, miny;
static float scale;
-static void InitDebugBitmap(void) {
+static void InitDebugBitmap() {
// this function allocates memory and clears the debug bitmap buffer
-
- if (bmp_buffer)
- free(bmp_buffer); // reliability check, free BMP buffer if already allocated
-
- bmp_buffer = NULL;
- bmp_buffer = (char *) malloc(DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT); // allocate memory
- if (bmp_buffer == NULL) {
- fprintf(stderr,
- "InitDebugBitmap(): unable to allocate %d kbytes for BMP buffer!\n",
- DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT / 1024);
- exit(1);
+ try {
+ bmp_buffer.assign(static_cast(DEBUG_BMP_WIDTH) * DEBUG_BMP_HEIGHT, 14);
+ }
+ catch (const std::bad_alloc& e) {
+ std::fprintf(stderr, "InitDebugBitmap(): unable to allocate %d kbytes for BMP buffer! Error: %s\n",
+ DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT / 1024, e.what());
+ bmp_buffer.clear(); // Ensure buffer is in a valid state
}
-
- memset(bmp_buffer, 14, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT); // Set all to all white (and allow for darker palette)
}
// Draw a small cross
-static void DrawPoint(const Vector v, unsigned char color) {
- int offset, x0, y0;
-
- if (bmp_buffer == NULL) {
- fprintf(stderr,
- "DrawLineInDebugBitmap(): function called with NULL BMP buffer!\n");
+static void DrawPoint(const Vector& v, const unsigned char color) {
+ if (bmp_buffer.empty()) {
return; // reliability check: cancel if bmp buffer unallocated
}
// translate the world coordinates in image pixel coordinates
- x0 = (int) ((v.x - minx) / scale);
- y0 = (int) ((v.y - miny) / scale);
+ const int x0 = static_cast((v.x - minx) / scale);
+ const int y0 = static_cast((v.y - miny) / scale);
- offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf(stderr,
+ const int offset = y0 * DEBUG_BMP_WIDTH + x0;
+ if (offset < 0 || offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) {
+ std::fprintf(stderr,
"DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n",
offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1);
+ std::exit(1);
}
bmp_buffer[offset] = color; // draw the point itself
@@ -4099,29 +4127,26 @@ static void DrawPoint(const Vector v, unsigned char color) {
// From PMB and Botman's code
-static void DrawLineInDebugBitmap(const Vector v_from, const Vector v_to, unsigned char color) {
+static void DrawLineInDebugBitmap(const Vector& v_from, const Vector& v_to, const unsigned char color) {
// blind copy of botman's Bresenham(). This function prints a vector line into a bitmap dot
// matrix. The dot matrix (bmp_buffer) is a global array. The size of the bitmap is always
// assumed to be DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT pixels (currently 2000 * 2000 to fit with
// the size of the universe, with an adaptative unit scale, up to 1 pixel = 10 vector units).
- int x0, y0, x1, y1;
- int dx, stepx, dy, stepy;
- int offset, fraction;
+ int stepx, stepy;
+ int fraction;
- if (bmp_buffer == NULL) {
- fprintf(stderr,
- "DrawLineInDebugBitmap(): function called with NULL BMP buffer!\n");
+ if (bmp_buffer.empty()) {
return; // reliability check: cancel if bmp buffer unallocated
}
// translate the world coordinates in image pixel coordinates
- x0 = (int) ((v_from.x - minx) / scale);
- y0 = (int) ((v_from.y - miny) / scale);
- x1 = (int) ((v_to.x - minx) / scale);
- y1 = (int) ((v_to.y - miny) / scale);
+ int x0 = static_cast((v_from.x - minx) / scale);
+ int y0 = static_cast((v_from.y - miny) / scale);
+ const int x1 = static_cast((v_to.x - minx) / scale);
+ const int y1 = static_cast((v_to.y - miny) / scale);
- dx = (x1 - x0) * 2;
- dy = (y1 - y0) * 2;
+ int dx = (x1 - x0) * 2;
+ int dy = (y1 - y0) * 2;
if (dx < 0) {
dx = -dx;
stepx = -1;
@@ -4133,12 +4158,12 @@ static void DrawLineInDebugBitmap(const Vector v_from, const Vector v_to, unsign
} else
stepy = 1;
- offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0) || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf(stderr,
+ int offset = y0 * DEBUG_BMP_WIDTH + x0;
+ if (offset < 0 || offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) {
+ std::fprintf(stderr,
"DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n",
offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1);
+ std::exit(1);
}
bmp_buffer[offset] = color; // draw the first point of the line
@@ -4162,12 +4187,12 @@ static void DrawLineInDebugBitmap(const Vector v_from, const Vector v_to, unsign
// compute the offset in the BMP buffer corresponding to this point
offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0)
- || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf(stderr,
+ if (offset < 0
+ || offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) {
+ std::fprintf(stderr,
"DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n",
offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1);
+ std::exit(1);
}
bmp_buffer[offset] = color; // set this point to have the specified color
@@ -4190,217 +4215,203 @@ static void DrawLineInDebugBitmap(const Vector v_from, const Vector v_to, unsign
// compute the offset in the BMP buffer corresponding to this point
offset = y0 * DEBUG_BMP_WIDTH + x0;
- if ((offset < 0)
- || (offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT)) {
- fprintf(stderr,
+ if (offset < 0
+ || offset >= DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT) {
+ std::fprintf(stderr,
"DrawLineInDebugBitmap(): bad BMP buffer index %d (range 0 - %d)\n",
offset, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT);
- exit(1);
+ std::exit(1);
}
bmp_buffer[offset] = color; // set this point to have the specified color
}
}
- return; // finished, segment has been printed into the BMP dot matrix
+ //return; // finished, segment has been printed into the BMP dot matrix
}
-// from PMB & Botman code
-
-static void WriteDebugBitmap(const char *filename) {
- // this function writes the debug bitmap image buffer in a .BMP file to disk. The format is
- // 256 color and 2000 * 2000 pixels. The center of the world being roughly the center of the
- // bitmap. The bitmap is stored in the file specified by 'filename' (which can be a relative
- // path from the Half-Life base directory).
- FILE *fp;
+static void WriteDebugBitmap(const char* filename) {
int data_start, file_size;
unsigned long dummy;
- if (bmp_buffer == NULL) {
- fprintf(stderr,
- "WriteDebugBitmap(): function called with NULL BMP buffer!\n");
+ if (bmp_buffer.empty()) {
+ std::fprintf(stderr,
+ "WriteDebugBitmap(): function called with NULL BMP buffer!\n");
return; // reliability check: cancel if bmp buffer unallocated
}
// open (or create) the .bmp file for writing in binary mode...
- fp = fopen(filename, "wb");
- if (fp == NULL) {
- fprintf(stderr, "WriteDebugBitmap(): unable to open BMP file!\n");
- if (bmp_buffer)
- free(bmp_buffer); // cannot open file, free DXF buffer
- bmp_buffer = NULL;
+ FILE* fp = std::fopen(filename, "wb");
+ if (fp == nullptr) {
+ std::fprintf(stderr, "WriteDebugBitmap(): unable to open BMP file!\n");
+ bmp_buffer.clear(); // Ensure buffer is in a valid state
return; // cancel if error creating file
}
// write the BMP header
- fwrite("BM", 2, 1, fp); // write the BMP header tag
- fseek(fp, sizeof(unsigned long), SEEK_CUR); // skip the file size field (will write it last)
- fwrite("\0\0", sizeof(short), 1, fp); // dump zeros in the first reserved field (unused)
- fwrite("\0\0", sizeof(short), 1, fp); // dump zeros in the second reserved field (unused)
- fseek(fp, sizeof(unsigned long), SEEK_CUR); // skip the data start field (will write it last)
+ constexpr char bmp_magic[] = { 'B', 'M' };
+ std::fwrite(bmp_magic, sizeof(bmp_magic), 1, fp); // write the BMP header tag
+ std::fseek(fp, sizeof(unsigned long), SEEK_CUR); // skip the file size field (will write it last)
+ constexpr short reserved = 0;
+ std::fwrite(&reserved, sizeof(short), 1, fp); // dump zeros in the first reserved field (unused)
+ std::fwrite(&reserved, sizeof(short), 1, fp); // dump zeros in the second reserved field (unused)
+ std::fseek(fp, sizeof(unsigned long), SEEK_CUR); // skip the data start field (will write it last)
// write the info header
dummy = 40;
- fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the info header size (does 40 bytes)
+ std::fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the info header size (does 40 bytes)
dummy = DEBUG_BMP_WIDTH;
- fwrite(&dummy, sizeof(long), 1, fp); // write the image width (2000 px)
+ std::fwrite(&dummy, sizeof(long), 1, fp); // write the image width (2000 px)
dummy = DEBUG_BMP_HEIGHT;
- fwrite(&dummy, sizeof(long), 1, fp); // write the image height (2000 px)
+ std::fwrite(&dummy, sizeof(long), 1, fp); // write the image height (2000 px)
dummy = 1;
- fwrite(&dummy, sizeof(short), 1, fp); // write the # of planes (1)
+ std::fwrite(&dummy, sizeof(short), 1, fp); // write the # of planes (1)
dummy = 8;
- fwrite(&dummy, sizeof(short), 1, fp); // write the bit count (8)
+ std::fwrite(&dummy, sizeof(short), 1, fp); // write the bit count (8)
dummy = 0;
- fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the compression id (no compression)
+ std::fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the compression id (no compression)
dummy = DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT;
- fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the image size (2000 * 2000)
+ std::fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the image size (2000 * 2000)
dummy = 0;
- fwrite(&dummy, sizeof(long), 1, fp); // write the X pixels per meter (not specified)
- fwrite(&dummy, sizeof(long), 1, fp); // write the Y pixels per meter (not specified)
+ std::fwrite(&dummy, sizeof(long), 1, fp); // write the X pixels per meter (not specified)
+ std::fwrite(&dummy, sizeof(long), 1, fp); // write the Y pixels per meter (not specified)
dummy = 256;
- fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the # of colors used (all)
- fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the # of important colors (wtf ?)
+ std::fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the # of colors used (all)
+ std::fwrite(&dummy, sizeof(unsigned long), 1, fp); // write the # of important colors (wtf ?)
// write the color palette (B, G, R, reserved byte)
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0x00, fp); // 0=BLACK
- fputc(0xFF, fp);
- fputc(0xFF, fp);
- fputc(0xFF, fp);
- fputc(0x00, fp); // 1=WHITE
- fputc(0x80, fp);
- fputc(0x80, fp);
- fputc(0x80, fp);
- fputc(0x00, fp); // 2=GREY
- fputc(0xC0, fp);
- fputc(0xC0, fp);
- fputc(0xC0, fp);
- fputc(0x00, fp); // 3=SILVER
- fputc(0x80, fp);
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0x00, fp); // 4=DARK BLUE
- fputc(0xFF, fp);
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0x00, fp); // 5=BLUE
- fputc(0x80, fp);
- fputc(0x80, fp);
- fputc(0x00, fp);
- fputc(0x00, fp); // 6=DARK YELLOW
- fputc(0xFF, fp);
- fputc(0xFF, fp);
- fputc(0x00, fp);
- fputc(0x00, fp); // 7=YELLOW ? LIGHT BLUE
- fputc(0x00, fp);
- fputc(0x80, fp);
- fputc(0x00, fp);
- fputc(0x00, fp); // 8=DARK GREEN
- fputc(0x00, fp);
- fputc(0xFF, fp);
- fputc(0x00, fp);
- fputc(0x00, fp); // 9=GREEN
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0x80, fp);
- fputc(0x00, fp); // 10=DARK RED
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0xFF, fp);
- fputc(0x00, fp); // 11=RED
- fputc(0x80, fp);
- fputc(0x00, fp);
- fputc(0x80, fp);
- fputc(0x00, fp); // 12=DARK PURPLE
- fputc(0xFF, fp);
- fputc(0x00, fp);
- fputc(0xFF, fp);
- fputc(0x00, fp); // 13=PURPLE
- fputc(0xFF, fp);
- fputc(0xFF, fp);
- fputc(0xFF, fp);
- fputc(0x00, fp); // 14=WHITE
- fputc(0xEF, fp);
- fputc(0xEF, fp);
- fputc(0xEF, fp);
- fputc(0x00, fp); // 15=WHITE-GREY
- fputc(0xDF, fp);
- fputc(0xDF, fp);
- fputc(0xDF, fp);
- fputc(0x00, fp); // 16=GREY
- fputc(0xCF, fp);
- fputc(0xCF, fp);
- fputc(0xCF, fp);
- fputc(0x00, fp); // 17=DARKGREY
- fputc(0xBF, fp);
- fputc(0xBF, fp);
- fputc(0xBF, fp);
- fputc(0x00, fp); // 18=DARKGREY
- fputc(0xAF, fp);
- fputc(0xAF, fp);
- fputc(0xAF, fp);
- fputc(0x00, fp); // 19=DARKGREY
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp); // 0=BLACK
+ std::fputc(0xFF, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp); // 1=WHITE
+ std::fputc(0x80, fp);
+ std::fputc(0x80, fp);
+ std::fputc(0x80, fp);
+ std::fputc(0x00, fp); // 2=GREY
+ std::fputc(0xC0, fp);
+ std::fputc(0xC0, fp);
+ std::fputc(0xC0, fp);
+ std::fputc(0x00, fp); // 3=SILVER
+ std::fputc(0x80, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp); // 4=DARK BLUE
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp); // 5=BLUE
+ std::fputc(0x80, fp);
+ std::fputc(0x80, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp); // 6=DARK YELLOW
+ std::fputc(0xFF, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp); // 7=YELLOW ? LIGHT BLUE
+ std::fputc(0x00, fp);
+ std::fputc(0x80, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp); // 8=DARK GREEN
+ std::fputc(0x00, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp); // 9=GREEN
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x80, fp);
+ std::fputc(0x00, fp); // 10=DARK RED
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp); // 11=RED
+ std::fputc(0x80, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x80, fp);
+ std::fputc(0x00, fp); // 12=DARK PURPLE
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp); // 13=PURPLE
+ std::fputc(0xFF, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0xFF, fp);
+ std::fputc(0x00, fp); // 14=WHITE
+ std::fputc(0xEF, fp);
+ std::fputc(0xEF, fp);
+ std::fputc(0xEF, fp);
+ std::fputc(0x00, fp); // 15=WHITE-GREY
+ std::fputc(0xDF, fp);
+ std::fputc(0xDF, fp);
+ std::fputc(0xDF, fp);
+ std::fputc(0x00, fp); // 16=GREY
+ std::fputc(0xCF, fp);
+ std::fputc(0xCF, fp);
+ std::fputc(0xCF, fp);
+ std::fputc(0x00, fp); // 17=DARKGREY
+ std::fputc(0xBF, fp);
+ std::fputc(0xBF, fp);
+ std::fputc(0xBF, fp);
+ std::fputc(0x00, fp); // 18=DARKGREY
+ std::fputc(0xAF, fp);
+ std::fputc(0xAF, fp);
+ std::fputc(0xAF, fp);
+ std::fputc(0x00, fp); // 19=DARKGREY
for (dummy = 20; dummy < 256; dummy++) {
// fill out the rest of the palette with zeros
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0x00, fp);
- fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
+ std::fputc(0x00, fp);
}
// write the actual image data
data_start = ftell(fp); // get the data start position (that's where we are now)
- fwrite(bmp_buffer, DEBUG_BMP_WIDTH * DEBUG_BMP_HEIGHT, 1, fp); // write the image
+ std::fwrite(bmp_buffer.data(), bmp_buffer.size(), 1, fp); // write the image
file_size = ftell(fp); // get the file size now that the image is dumped
// now that we've dumped our data, we know the file size and the data start position
- fseek(fp, 0, SEEK_SET); // rewind
- fseek(fp, 2, SEEK_CUR); // skip the BMP header tag "BM"
- fwrite(&file_size, sizeof(unsigned long), 1, fp); // write the file size at its location
- fseek(fp, sizeof(short), SEEK_CUR); // skip the first reserved field
- fseek(fp, sizeof(short), SEEK_CUR); // skip the second reserved field
- fwrite(&data_start, sizeof(unsigned long), 1, fp); // write the data start at its location
+ std::fseek(fp, 0, SEEK_SET); // rewind
+ std::fseek(fp, 2, SEEK_CUR); // skip the BMP header tag "BM"
+ std::fwrite(&file_size, sizeof(unsigned long), 1, fp); // write the file size at its location
+ std::fseek(fp, sizeof(short), SEEK_CUR); // skip the first reserved field
+ std::fseek(fp, sizeof(short), SEEK_CUR); // skip the second reserved field
+ std::fwrite(&data_start, sizeof(unsigned long), 1, fp); // write the data start at its location
- fclose(fp); // finished, close the BMP file
+ std::fclose(fp); // finished, close the BMP file
- if (bmp_buffer)
- free(bmp_buffer); // and free the BMP buffer
- bmp_buffer = NULL;
+ bmp_buffer.clear(); // and free the BMP buffer
+ bmp_buffer.shrink_to_fit();
- return; // and return
+ //return; // and return
}
// Find the border of all nodes to scale the bitmap
-void cNodeMachine::FindMinMax(void) {
- int i;
- float scalex, scaley;
-
- minx = miny = 9999.0;
- maxx = maxy = -9999.0;
- for (i = 0;
- (i < MAX_NODES) && (Nodes[i].origin != Vector(9999, 9999, 9999));
+void cNodeMachine::FindMinMax() const
+{
+ minx = miny = 9999.0f;
+ maxx = maxy = -9999.0f;
+ for (int i = 0;
+ i < MAX_NODES && Nodes[i].origin != Vector(9999, 9999, 9999);
i++) {
- if (Nodes[i].origin.x > maxx)
- maxx = Nodes[i].origin.x;
- if (Nodes[i].origin.y > maxy)
- maxy = Nodes[i].origin.y;
- if (Nodes[i].origin.x < minx)
- minx = Nodes[i].origin.x;
- if (Nodes[i].origin.y < miny)
- miny = Nodes[i].origin.y;
+ maxx = std::max(Nodes[i].origin.x, maxx);
+ maxy = std::max(Nodes[i].origin.y, maxy);
+ minx = std::min(Nodes[i].origin.x, minx);
+ miny = std::min(Nodes[i].origin.y, miny);
}
// Avoid having lines/points just on the bitmap border, add some more spaces
- maxx += NODE_ZONE;
- minx -= NODE_ZONE;
- maxy += NODE_ZONE;
- miny -= NODE_ZONE;
+ maxx += static_cast(NODE_ZONE);
+ minx -= static_cast(NODE_ZONE);
+ maxy += static_cast(NODE_ZONE);
+ miny -= static_cast(NODE_ZONE);
// first compute the X and Y divider scale, and take the greatest of both
- scalex = (1 + maxx - minx) / DEBUG_BMP_WIDTH;
- scaley = (1 + maxy - miny) / DEBUG_BMP_WIDTH;
+ const float scalex = (1 + maxx - minx) / static_cast(DEBUG_BMP_WIDTH);
+ const float scaley = (1 + maxy - miny) / static_cast(DEBUG_BMP_WIDTH);
if (scalex > scaley)
scale = scalex + scalex / 100; // add a little offset (margin) for safety
else
@@ -4412,35 +4423,36 @@ void cNodeMachine::FindMinMax(void) {
// Palette is defined such that increasing the palette index
// Makes a slightly darker dark
-void cNodeMachine::MarkAxis(void) {
- int x, y, x0, y0;
+// Mark X and Y axis
+void cNodeMachine::MarkAxis()
+{
+ int x, y;
- x0 = (int) ((0 - minx) / scale);
- y0 = (int) ((0 - miny) / scale);
+ // Mark X axis
+ y = static_cast((0 - miny) / scale);
+ if (y >= 0 && y < DEBUG_BMP_HEIGHT)
+ for (x = 0; x < DEBUG_BMP_WIDTH; x++)
+ bmp_buffer[y * DEBUG_BMP_WIDTH + x] = 17;
- // Mark X axis by keeping X to 0 and varying Y
- if ((minx < 0) && (0 < maxx))
+ // Mark Y axis
+ x = static_cast((0 - minx) / scale);
+ if (x >= 0 && x < DEBUG_BMP_WIDTH)
for (y = 0; y < DEBUG_BMP_HEIGHT; y++)
- bmp_buffer[y * DEBUG_BMP_WIDTH + x0] += 2;
-
- // Mark Y axis by keeping Y to 0 and varying X
- if ((miny < 0) && (0 < maxy))
- for (x = 0; x < DEBUG_BMP_WIDTH; x++)
- bmp_buffer[y0 * DEBUG_BMP_WIDTH + x] += 2;
+ bmp_buffer[y * DEBUG_BMP_WIDTH + x] = 17;
}
// 05/07/04
// Mark each meredians (default 256 units) of alternating color
-void cNodeMachine::MarkMeredians(void) {
+void cNodeMachine::MarkMeredians() {
int x, y;
int Meredian;
// Mark some meredians
for (x = 0; x < DEBUG_BMP_WIDTH; x++) {
- Meredian =
- (int) ((float) x * scale + minx +
- 8192.0) / (float) SIZE_MEREDIAN;
+ Meredian = static_cast(
+ (x * scale + minx +
+ 8192.0f) / static_cast(SIZE_MEREDIAN));
if (Meredian & 0x01) {
for (y = 0; y < DEBUG_BMP_HEIGHT; y++)
bmp_buffer[y * DEBUG_BMP_WIDTH + x]++;
@@ -4449,9 +4461,9 @@ void cNodeMachine::MarkMeredians(void) {
// Mark some meredians
for (y = 0; y < DEBUG_BMP_HEIGHT; y++) {
- Meredian =
- (int) ((float) y * scale + miny +
- 8192.0) / (float) SIZE_MEREDIAN;
+ Meredian = static_cast(
+ (y * scale + miny +
+ 8192.0f) / static_cast(SIZE_MEREDIAN));
if (Meredian & 0x01) {
for (x = 0; x < DEBUG_BMP_HEIGHT; x++)
bmp_buffer[y * DEBUG_BMP_WIDTH + x]++;
@@ -4461,52 +4473,50 @@ void cNodeMachine::MarkMeredians(void) {
// Put a cross on all nodes in RBN + draw lines to all neighbours
-void cNodeMachine::PlotNodes(int NeighbourColor, int NodeColor) {
- int i, j;
+void cNodeMachine::PlotNodes(const unsigned char NeighbourColor, const unsigned char NodeColor) const
+{
+ int i;
// Draw all neighbours
for (i = 0;
- (i < MAX_NODES) && (Nodes[i].origin != Vector(9999, 9999, 9999));
+ i < MAX_NODES && Nodes[i].origin != Vector(9999, 9999, 9999);
i++)
- for (j = 0; (j < MAX_NEIGHBOURS) && (Nodes[i].iNeighbour[j] >= 0);
+ for (int j = 0; j < MAX_NEIGHBOURS && Nodes[i].iNeighbour[j] >= 0;
j++)
DrawLineInDebugBitmap(Nodes[i].origin,
Nodes[Nodes[i].iNeighbour[j]].origin,
NeighbourColor);
// Draw all nodes
for (i = 0;
- (i < MAX_NODES) && (Nodes[i].origin != Vector(9999, 9999, 9999));
+ i < MAX_NODES && Nodes[i].origin != Vector(9999, 9999, 9999);
i++)
DrawPoint(Nodes[i].origin, NodeColor);
}
// Put a small cross at all goal points
-void cNodeMachine::PlotGoals(int color) {
- int i;
- Vector v;
-
- for (i = 0; (i < MAX_GOALS) && (Goals[i].iNode >= 0); i++) {
- v = Nodes[Goals[i].iNode].origin;
+void cNodeMachine::PlotGoals(const unsigned char color) const
+{
+ for (int i = 0; i < MAX_GOALS && Goals[i].iNode >= 0; i++) {
+ const Vector v = Nodes[Goals[i].iNode].origin;
DrawPoint(v, color);
}
}
// Plot the computed paths for all life bots
-void cNodeMachine::PlotPaths(int Tcolor, int CTcolor) {
- int i, iBot, From, To;
-
- for (iBot = 0; (iBot < 32); iBot++) {
+void cNodeMachine::PlotPaths(const unsigned char Tcolor, const unsigned char CTcolor) const
+{
+ for (int iBot = 0; iBot < 32; iBot++) {
if (bots[iBot].bIsUsed) {
- From = iPath[iBot][0];
+ int From = iPath[iBot][0];
if (From < 0)
continue; // This bot has not path
- for (i = 1; (i < MAX_NODES) && (iPath[iBot][i] >= 0); i++) {
- To = iPath[iBot][i];
+ for (int i = 1; i < MAX_NODES && iPath[iBot][i] >= 0; i++) {
+ const int To = iPath[iBot][i];
DrawLineInDebugBitmap(Nodes[From].origin, Nodes[To].origin,
- (bots[iBot].iTeam ==
- 1) ? Tcolor : CTcolor);
+ bots[iBot].iTeam ==
+ 1 ? Tcolor : CTcolor);
From = To;
}
}
@@ -4519,7 +4529,8 @@ void cNodeMachine::PlotPaths(int Tcolor, int CTcolor) {
// 05/07/04
// Marking Axis, Meredians, other colors, other filenames (linked to map names)
-void cNodeMachine::Draw(void) {
+void cNodeMachine::Draw() const
+{
static int Count = 0; // Static to create filenames like cs_siege0000.bmp, cs_siege0001.bmp, ...
char Filename[80];
@@ -4530,11 +4541,12 @@ void cNodeMachine::Draw(void) {
PlotNodes(0, 5); // 0 = black, 5 = blue
PlotPaths(11, 7); // 11 = Red 7 = light blue ?
PlotGoals(9); // 9 = green
- sprintf(Filename, "%s%4.4d.bmp", STRING(gpGlobals->mapname), Count++);
+ snprintf(Filename, sizeof(Filename), "%s%4.4d.bmp", STRING(gpGlobals->mapname), Count++);
WriteDebugBitmap(Filename);
}
-void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit) {
+void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit) const
+{
pBot->rprint_trace("cNodeMachine::ExecuteDoorInteractionLogic", "Start");
// check if we have to 'use' it
@@ -4546,9 +4558,9 @@ void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit)
pBot->vHead = VecBModelOrigin(pEntityHit);
pBot->vBody = pBot->vHead;
UTIL_BotPressKey(pBot, IN_USE);
- pBot->setTimeToWait(0.5);
+ pBot->setTimeToWait(0.5f);
pBot->fButtonTime = gpGlobals->time + 5;
- pBot->pButtonEdict = NULL;
+ pBot->pButtonEdict = nullptr;
pBot->rprint_trace("cNodeMachine::ExecuteDoorInteractionLogic", "I have pressed USE to open a door - finished");
// TODO: when this door is opened by a trigger_multiple (on touch)
@@ -4560,23 +4572,22 @@ void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit)
const char *doorButtonToLookFor = STRING(pEntityHit->v.targetname);
if (doorButtonToLookFor) {
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "There is a target button , named %s, to open this door [%s] - going to search for it.", doorButtonToLookFor, STRING(pEntityHit->v.classname));
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "There is a target button , named %s, to open this door [%s] - going to search for it.", doorButtonToLookFor, STRING(pEntityHit->v.classname));
pBot->rprint_trace("cNodeMachine::ExecuteDoorInteractionLogic", msg);
// find this entity
- edict_t *pButtonEdict = NULL;
- edict_t *pent = NULL;
+ edict_t *pButtonEdict = nullptr;
+ edict_t *pent = nullptr;
TraceResult trb;
// search for all buttons
- while ((pent = UTIL_FindEntityByClassname(pent, "func_button")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "func_button")) != nullptr) {
// skip anything that could be 'self' (unlikely)
if (pent == pEntityHit) continue;
// found button entity matching target
- if (strcmp(STRING(pent->v.target), doorButtonToLookFor) == 0) {
+ if (std::strcmp(STRING(pent->v.target), doorButtonToLookFor) == 0) {
Vector buttonVector = VecBModelOrigin(pent);
UTIL_TraceLine(pBot->pEdict->v.origin, buttonVector,
@@ -4584,34 +4595,33 @@ void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit)
pBot->pEdict, &trb);
// if nothing hit:
- if (trb.flFraction >= 1.0) {
+ if (trb.flFraction >= 1.0f) {
// Button found to head for!
pButtonEdict = pent;
break;
- } else {
- // we hit this button we check for
- if (trb.pHit == pent) {
- // Button found to head for!
- pButtonEdict = pent;
- break;
- }
+ }
+ // we hit this button we check for
+ if (trb.pHit == pent) {
+ // Button found to head for!
+ pButtonEdict = pent;
+ break;
}
}
} // while (func_button)
// still nothing found
- if (pButtonEdict == NULL) {
+ if (pButtonEdict == nullptr) {
// TOUCH buttons (are not func_button!)
- pent = NULL;
+ pent = nullptr;
// search for all buttons
- while ((pent = UTIL_FindEntityByClassname(pent, "trigger_multiple")) != NULL) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "trigger_multiple")) != nullptr) {
// skip anything that could be 'self' (unlikely)
if (pent == pEntityHit)
continue;
// found button entity
- if (strcmp(STRING(pent->v.target), doorButtonToLookFor) == 0) {
+ if (std::strcmp(STRING(pent->v.target), doorButtonToLookFor) == 0) {
// get vectr
Vector vPentVector = VecBModelOrigin(pent);
@@ -4622,14 +4632,13 @@ void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit)
bool isGood = false;
// if nothing hit:
- if (trb.flFraction >= 1.0) {
+ if (trb.flFraction >= 1.0f) {
pButtonEdict = pent;
break;
- } else {
- // we hit this button we check for
- if (trb.pHit == pent)
- isGood = true;
}
+ // we hit this button we check for
+ if (trb.pHit == pent)
+ isGood = true;
if (isGood) {
// Button found to head for!
@@ -4639,13 +4648,13 @@ void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit)
// as most doors have 2 buttons to access it (ie prodigy)
// hits by worldspawn here
- if (strcmp(STRING(trb.pHit->v.classname), "worldspawn") == 0) {
+ if (std::strcmp(STRING(trb.pHit->v.classname), "worldspawn") == 0) {
// DE_PRODIGY FIX:
// Somehow the button is not detectable. Find a node, that is close to it.
// then retry the traceline. It should NOT hit a thing now.
// On success, it is still our button
- int iClose = getClosestNode(vPentVector, NODE_ZONE, pent);
+ const int iClose = getClosestNode(vPentVector, NODE_ZONE, pent);
if (iClose > -1) {
// retry the tracehull
@@ -4656,7 +4665,7 @@ void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit)
pBot->pEdict, &trb);
// if nothing hit:
- if (trb.flFraction >= 1.0) {
+ if (trb.flFraction >= 1.0f) {
pButtonEdict = pent;
break;
}
@@ -4670,22 +4679,22 @@ void cNodeMachine::ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pEntityHit)
// We have found a button to go to
if (pButtonEdict) {
- memset(msg, 0, sizeof(msg));
+ std::memset(msg, 0, sizeof(msg));
// Get its vector
- Vector vButtonVector = VecBModelOrigin(pButtonEdict);
+ const Vector vButtonVector = VecBModelOrigin(pButtonEdict);
// Search a node close to it
- int iButtonNode = getClosestNode(vButtonVector, NODE_ZONE, pButtonEdict);
+ const int iButtonNode = getClosestNode(vButtonVector, NODE_ZONE, pButtonEdict);
// When node found, create path to it
if (pBot->createPath(iButtonNode, PATH_NONE)) {
- sprintf(msg, "Found a button at node %d and created a path to it.", iButtonNode);
+ snprintf(msg, sizeof(msg), "Found a button at node %d and created a path to it.", iButtonNode);
pBot->pButtonEdict = pButtonEdict;
} else {
if (iButtonNode > -1) {
- sprintf(msg, "Found a button at node %d but failed to create a path to it.", iButtonNode);
+ snprintf(msg, sizeof(msg), "Found a button at node %d but failed to create a path to it.", iButtonNode);
} else {
- sprintf(msg, "Found a button, but there is no nearby node :/");
+ snprintf(msg, sizeof(msg), "Found a button, but there is no nearby node :/");
}
}
pBot->rprint_trace("cNodeMachine::ExecuteDoorInteractionLogic", msg);
diff --git a/NodeMachine.h b/NodeMachine.h
index 18e3a0e..604ee82 100644
--- a/NodeMachine.h
+++ b/NodeMachine.h
@@ -35,7 +35,12 @@
#ifndef NODEMACHINE_H
#define NODEMACHINE_H
+#include
+#include
+#include
+
#include "bot.h"
+#include "game.h"
#include "NodeDataTypes.h"
@@ -43,15 +48,15 @@
class cNodeMachine {
public:
// -----------------
- int addNode(Vector vOrigin, edict_t *pEntity);
+ int addNode(const Vector& vOrigin, edict_t *pEntity);
- int Reachable(const int iStart, const int iEnd);
+ int Reachable(int iStart, int iEnd) const;
- int add2(Vector vOrigin, int iType, edict_t *pEntity);
+ int add2(const Vector& vOrigin, int iType, edict_t *pEntity);
- int getClosestNode(Vector vOrigin, float fDist, edict_t *pEdict); // returns a close node
- int getFurthestNode(Vector vOrigin, float fDist, edict_t *pEdict); // returns a node within dist, but most far away
- int getFreeNodeIndex();
+ int getClosestNode(const Vector& vOrigin, float fDist, edict_t *pEdict) const; // returns a close node
+ int getFurthestNode(const Vector& vOrigin, float fDist, const edict_t *pEdict) const; // returns a node within dist, but most far away
+ int getFreeNodeIndex() const;
// -----------------
bool add_neighbour_node(int iNode, int iToNode);
@@ -60,28 +65,37 @@ class cNodeMachine {
bool remove_neighbour_nodes(int iNode);
- int freeNeighbourNodeIndex(tNode *Node);
+ static int freeNeighbourNodeIndex(const tNode *Node);
- int is_neighbour_node(tNode node, int iNode);
+ static int is_neighbour_node(const tNode& node, int iNode);
// -----------------
void init(); // Init (info)nodes
- void save(); // Save nodes on disk
+
+ void initNodes();
+ void initInfoNodes();
+ void initializeNode(tNode& node);
+ void initTroubles();
+ void initPaths();
+ void initVisTable();
+ void initMeredians();
+
+ void save() const; // Save nodes on disk
void load(); // Load nodes on disk
- void save_important();
+ void save_important() const;
// -----------------
- Vector node_vector(int iNode);
+ Vector node_vector(int iNode) const;
// -----------------
- int GetTroubleIndexForConnection(int iFrom, int iTo);
+ int GetTroubleIndexForConnection(int iFrom, int iTo) const;
int AddTroubledConnection(int iFrom, int iTo);
bool IncreaseAttemptsForTroubledConnectionOrRemoveIfExceeded(int iFrom, int iTo);
- bool hasAttemptedConnectionTooManyTimes(int index);
+ bool hasAttemptedConnectionTooManyTimes(int index) const;
void IncreaseAttemptsForTroubledConnection(int index);
bool ClearTroubledConnection(int iFrom, int iTo);
@@ -90,24 +104,24 @@ class cNodeMachine {
void setUpInitialGoals(); // find new goals and attach them to the nodes
void updateGoals(); // update moving goals (ie hostages)
- int getGoalIndexFromNode(int iNode);
+ int getGoalIndexFromNode(int iNode) const;
void resetCheckedValuesForGoals();
void ClearImportantGoals();
- bool hasGoalWithEdict(edict_t *pEdict);
+ bool hasGoalWithEdict(edict_t *pEdict) const;
- void addGoal(edict_t *pEdict, int goalType, Vector vVec);
+ void addGoal(edict_t *pEdict, int goalType, const Vector& vVec);
tGoal * getRandomGoalByType(int goalType); // return a node close to a iType goal (random)
- bool node_float(Vector vOrigin, edict_t *pEdict);
+ static bool node_float(const Vector& vOrigin, edict_t *pEdict);
- bool node_on_crate(Vector vOrigin, edict_t *pEdict);
+ static bool node_on_crate(const Vector& vOrigin, edict_t *pEdict);
- int node_dangerous(int iTeam, Vector vOrigin, float fMaxDistance);
+ int node_dangerous(int iTeam, const Vector& vOrigin, float fMaxDistance);
- int node_look_camp(Vector vOrigin, int iTeam, edict_t *pEdict);
+ int node_look_camp(const Vector& vOrigin, int iTeam, edict_t *pEdict);
// -----------------
void danger(int iNode, int iTeam); // Make spot dangerous
@@ -125,30 +139,30 @@ class cNodeMachine {
// -----------------
int node_cover(int iFrom, int iTo, edict_t *pEdict);
- int node_look_at_hear(int iFrom, int iTo, edict_t *pEdict);
-
- int node_camp(Vector vOrigin, int iTeam);
+ int node_look_at_hear(int iFrom, int iOrigin, edict_t* pEdict);
+
+ int node_camp(const Vector& vOrigin, int iTeam) const;
void vis_calculate(int iFrom);
// -----------------
bool createPath(int nodeStartIndex, int nodeTargetIndex, int botIndex, cBot *pBot, int iFlags); // know the path
- void path_draw(edict_t *pEntity); // draw the path
+ void path_draw(edict_t *pEntity) const; // draw the path
void path_walk(cBot *pBot, float distanceMoved); // walk the path
void path_think(cBot *pBot, float distanceMoved); // think about paths
void path_clear(int botIndex);
void ExecuteNearNodeLogic(cBot *pBot);
- int getNodeIndexFromBotForPath(int botIndex, int pathNodeIndex);
+ int getNodeIndexFromBotForPath(int botIndex, int pathNodeIndex) const;
// -----------------
- void VectorToMeredian(Vector vOrigin, int *iX, int *iY); // Input: origin, output X and Y Meredians
+ static void VectorToMeredian(const Vector& vOrigin, int *iX, int *iY); // Input: origin, output X and Y Meredians
void AddToMeredian(int iX, int iY, int iNode);
// -----------------
- void draw(edict_t *pEntity); // Draw nodes
- void connections(edict_t *pEntity); // Draw neighbours
+ void draw(edict_t *pEntity) const; // Draw nodes
+ void connections(edict_t *pEntity) const; // Draw neighbours
// -----------------
void addNodesForPlayers(); // Players plot around!
@@ -157,57 +171,64 @@ class cNodeMachine {
// -------------------
// From cheesemonster:
- int GetVisibilityFromTo(int iFrom, int iTo); // BERKED
- void ClearVisibilityTable(void);
+ int GetVisibilityFromTo(int iFrom, int iTo) const; // BERKED
+ void ClearVisibilityTable();
void SetVisibilityFromTo(int iFrom, int iTo, bool bVisible);
- void FreeVisibilityTable(void);
+ void FreeVisibilityTable();
// Some debugging by EVY
- void dump_goals(void);
+ void dump_goals() const;
- void dump_path(int iBot, int ThisNode);
+ void dump_path(int iBot, int CurrentPath) const;
- void Draw(void);
+ void Draw() const;
tNode *getNode(int index);
tGoal *getGoal(int index);
private:
- tNode Nodes[MAX_NODES]; // Nodes
- tInfoNode InfoNodes[MAX_NODES]; // Info for Nodes (metadata)
- tPlayer Players[32]; // Players to keep track of, for node plotting
- tGoal Goals[MAX_GOALS]; // Goals to pursue in the game
- tMeredian Meredians[MAX_MEREDIANS][MAX_MEREDIANS]; // Meredian lookup search for Nodes, squared
+ tNode Nodes[MAX_NODES] = {}; // Nodes
+ tInfoNode InfoNodes[MAX_NODES] = {}; // Info for Nodes (metadata)
+ tPlayer Players[32] = {}; // Players to keep track of, for node plotting
+ tGoal Goals[MAX_GOALS] = {}; // Goals to pursue in the game
+ tMeredian Meredians[MAX_MEREDIANS][MAX_MEREDIANS] = {}; // Meredian lookup search for Nodes, squared
+
+ int iPath[MAX_BOTS][MAX_PATH_NODES] = {}; // 32 bots, with max waypoints paths (TODO: move to bot class?)
+
+ int iMaxUsedNodes = 0;
+
+ byte iVisChecked[MAX_NODES] = {};
+ std::vector cVisTable;
+ tTrouble Troubles[MAX_TROUBLE] = {};
+
+ void FindMinMax() const;
- int iPath[MAX_BOTS][MAX_PATH_NODES]; // 32 bots, with max waypoints paths (TODO: move to bot class?)
+ static void MarkAxis();
- int iMaxUsedNodes;
+ static void MarkMeredians();
- byte iVisChecked[MAX_NODES];
- unsigned char *cVisTable;
- tTrouble Troubles[MAX_TROUBLE];
+ void PlotNodes(unsigned char NeighbourColor, unsigned char NodeColor) const;
- void FindMinMax(void);
+ void PlotPaths(unsigned char Tcolor, unsigned char CTcolor) const;
- void MarkAxis(void);
+ void PlotGoals(unsigned char color) const;
- void MarkMeredians(void);
+ static void makeAllWaypointsAvailable();
- void PlotNodes(int NeighbourColor, int NodeColor);
+ static bool isValidNodeIndex(int index);
- void PlotPaths(int Tcolor, int CTcolor);
+ static bool isInvalidNode(int index);
- void PlotGoals(int GoalColor);
+ void buildPath(int nodeStartIndex, int nodeTargetIndex, int botIndex, cBot* pBot);
- void makeAllWaypointsAvailable() const;
+ static void closeNode(int nodeIndex, int parent, float cost);
- void closeNode(int nodeIndex, int parent, float cost);
- void openNeighbourNodes(int startNodeIndex, int nodeToOpenNeighboursFrom, int destinationNodeIndex, int botTeam);
+ void openNeighbourNodes(int startNodeIndex, int nodeToOpenNeighboursFrom, int destinationNodeIndex, int botTeam) const;
- char *getGoalTypeAsText(const tGoal &goal) const;
+ static std::string getGoalTypeAsText(const tGoal& goal);
int getFreeGoalIndex() const;
@@ -215,15 +236,15 @@ class cNodeMachine {
void initGoal(int g);
- bool isEntityDoor(const edict_t *pEntityHit) const;
- bool isEntityHostage(const edict_t *pEntityHit) const;
- bool isEntityWorldspawn(const edict_t *pEntityHit) const;
+ static bool isEntityDoor(const edict_t *pEntityHit);
+ static bool isEntityHostage(const edict_t *pEntityHit);
+ static bool isEntityWorldspawn(const edict_t *pEntityHit);
- bool isDoorThatOpensWhenPressingUseButton(const edict_t *pEntityHit) const;
+ static bool isDoorThatOpensWhenPressingUseButton(const edict_t *pEntityHit);
- void ExecuteIsStuckLogic(cBot *pBot, int currentNodeToHeadFor, Vector &vector);
+ void ExecuteIsStuckLogic(cBot *pBot, int currentNodeToHeadFor, const Vector &vector);
- void ExecuteDoorInteractionLogic(cBot *pBot, edict_t *pS);
+ void ExecuteDoorInteractionLogic(cBot* pBot, edict_t* pEntityHit) const;
};
#endif // NODEMACHINE_H
diff --git a/bin/data/cstrike/exp/.DS_Store b/bin/data/cstrike/exp/.DS_Store
deleted file mode 100644
index 5008ddf..0000000
Binary files a/bin/data/cstrike/exp/.DS_Store and /dev/null differ
diff --git a/bin/data/cstrike/maps/.DS_Store b/bin/data/cstrike/maps/.DS_Store
deleted file mode 100644
index 5008ddf..0000000
Binary files a/bin/data/cstrike/maps/.DS_Store and /dev/null differ
diff --git a/bin/dll/.DS_Store b/bin/dll/.DS_Store
deleted file mode 100644
index 5008ddf..0000000
Binary files a/bin/dll/.DS_Store and /dev/null differ
diff --git a/bot.cpp b/bot.cpp
index 714e380..b81e57f 100644
--- a/bot.cpp
+++ b/bot.cpp
@@ -1,4418 +1,4601 @@
-/**
- * RealBot : Artificial Intelligence
- * Version : Work In Progress
- * Author : Stefan Hendriks
- * Url : http://realbot.bots-united.com
- **
- * DISCLAIMER
- *
- * History, Information & Credits:
- * RealBot is based partially upon the HPB-Bot Template #3 by Botman
- * Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
- * Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
- * everybody else who helped me with this project.
- * Storage of Visibility Table using BITS by Cheesemonster.
- *
- * Some portions of code are from other bots, special thanks (and credits) go
- * to (in no specific order):
- *
- * Pierre Marie Baty
- * Count - Floyd
- *
- * !! BOTS-UNITED FOREVER !!
- *
- * This project is open-source, it is protected under the GPL license;
- * By using this source-code you agree that you will ALWAYS release the
- * source-code with your project.
- *
- **/
-
-
-/*
-
-//=========================================================
-// Returns if enemy can be shoot through some obstacle
-//=========================================================
-bool CBaseBot::IsShootableThruObstacle(Vector vecDest)
-{
- if (!WeaponShootsThru(m_iCurrentWeapon))
- return FALSE;
-
- Vector vecSrc = EyePosition();
- Vector vecDir = (vecDest - vecSrc).Normalize(); // 1 unit long
- Vector vecPoint = g_vecZero;
- int iThickness = 0;
- int iHits = 0;
-
- edict_t *pentIgnore = pev->pContainingEntity;
- TraceResult tr;
- UTIL_TraceLine(vecSrc, vecDest, ignore_monsters, ignore_glass, pentIgnore, &tr);
-
- while (tr.flFraction != 1.0 && iHits < 3)
- {
- iHits++;
- iThickness++;
- vecPoint = tr.vecEndPos + vecDir;
- while (POINT_CONTENTS(vecPoint) == CONTENTS_SOLID && iThickness < 64)
- {
- vecPoint = vecPoint + vecDir;
- iThickness++;
- }
- UTIL_TraceLine(vecPoint, vecDest, ignore_monsters, ignore_glass, pentIgnore, &tr);
- }
-
- if (iHits < 3 && iThickness < 64)
- {
- if (LengthSquared(vecDest - vecPoint) < 12544)
- return TRUE;
- }
-
- return FALSE;
-}
-
-*/
-
-#include
-#include
-#include
-#include
-#include
-
-#include "bot.h"
-#include "bot_weapons.h"
-#include "bot_func.h"
-
-#include "game.h"
-#include "NodeMachine.h"
-#include "ChatEngine.h"
-
-#include
-#include
-
-extern edict_t *pHostEdict;
-extern int mod_id;
-extern bool internet_play;
-extern cGame Game;
-extern cNodeMachine NodeMachine;
-extern cChatEngine ChatEngine;
-extern int counterstrike;
-//static FILE *fp;
-extern bool autoskill;
-
-/* Radio issue
- Credit by Ditlew (NNBOT - Rest In Peace) */
-bool radio_message = false;
-char *message = (char *) malloc(64 * sizeof(char));
-char radio_messenger[30];
-
-// random boundries
-extern int random_max_skill;
-extern int random_min_skill;
-cBot bots[32]; // max of 32 bots in a game
-
-// External added variables
-extern bool end_round; // End round
-
-#ifndef _WIN32
-#define _snprintf snprintf
-#endif
-
-cBot::cBot() {
- pBotHostage = NULL;
- fMoveToNodeTime = -1;
- clearHostages();
-}
-
-/******************************************************************************
- Function purpose: Initializes bot vars on spawn
- ******************************************************************************/
-void cBot::SpawnInit() {
- rprint_trace("SpawnInit()", "START");
-
- // ------------------------
- // TIMERS
- // ------------------------
- fUpdateTime = gpGlobals->time;
- fLastRunPlayerMoveTime = gpGlobals->time - 0.1f;
- fButtonTime = gpGlobals->time;
- fChatTime = gpGlobals->time + RANDOM_FLOAT(0.5, 5);
- fMemoryTime = gpGlobals->time;
- fDoRadio = gpGlobals->time;
- float freezeTimeCVAR = CVAR_GET_FLOAT("mp_freezetime");
- fNotStuckTime = gpGlobals->time + freezeTimeCVAR + 0.5f;
- f_shoot_wait_time = gpGlobals->time;
- f_goback_time = gpGlobals->time;
- f_may_jump_time = gpGlobals->time;
- fCheckHostageStatusTimer = gpGlobals->time;
- f_defuse = gpGlobals->time;
- f_allow_keypress = gpGlobals->time;
- f_use_timer = gpGlobals->time;
- f_light_time = gpGlobals->time;
- f_sec_weapon = gpGlobals->time;
- f_prim_weapon = gpGlobals->time;
- f_gren_time = gpGlobals->time;
- f_walk_time = gpGlobals->time;
- f_hear_time = gpGlobals->time;
- freezeTime = gpGlobals->time - 1;
- f_cover_time = gpGlobals->time;
- f_c4_time = gpGlobals->time;
- f_update_weapon_time = gpGlobals->time;
- f_follow_time = gpGlobals->time;
- f_jump_time = 0.0;
- f_hold_duck = gpGlobals->time;
- f_camp_time = gpGlobals->time;
- f_wait_time = gpGlobals->time;
- f_bot_see_enemy_time = gpGlobals->time;
- f_bot_find_enemy_time = gpGlobals->time;
- f_shoot_time = gpGlobals->time;
- fMoveToNodeTime = -1;
- nodeTimeIncreasedAmount = 0;
- distanceMovedTimer = gpGlobals->time;
- distanceMoved = 0;
- fBlindedTime = gpGlobals->time;
- f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.1, 0.9);
- fWanderTime = gpGlobals->time;
- f_strafe_time = gpGlobals->time;
-
- // Personality Related (these gets changed when loading personality file)
- fpXOffset = 0.0;
- fpYOffset = 0.0;
- fpZOffset = 0.0;
- fpMinReactTime = 0.0;
- fpMaxReactTime = 0.0;
-
- // ------------------------
- // POINTERS
- // ------------------------
- pButtonEdict = NULL;
- pBotHostage = NULL;
- clearHostages();
- pEnemyEdict = NULL;
-
- // chat
- memset(chChatSentence, 0, sizeof(chChatSentence));
-
-
- // ------------------------
- // INTEGERS
- // ------------------------
- iGoalNode = -1;
- goalIndex = -1;
- iPreviousGoalNode = -1;
- iCloseNode = -1;
- iDiedNode = -1;
-
- iTeam = -1;
- bot_class = -1;
- i_camp_style = 0;
- iPrimaryWeapon = -1;
- iSecondaryWeapon = -1;
- zoomed = ZOOM_NONE;
- play_rounds = RANDOM_LONG(Game.GetMinPlayRounds(), Game.GetMaxPlayRounds());
- bot_health = 0;
- prev_health = 0;
- bot_armor = 0;
- bot_weapons = 0;
- bot_use_special = 0 + RANDOM_LONG(0, 2);
- console_nr = 0;
- pathIndex = -1;
- iPathFlags = PATH_DANGER;
-
- // Smarter Stuck stuff
- iDuckTries = 0;
- iJumpTries = 0;
-
- // ------------------------
- // BOOLEANS
- // ------------------------
- vip = UTIL_IsVip(pEdict);
- bWalkKnife = false;
- buy_ammo_primary = true;
- buy_ammo_secondary = true;
- buy_primary = (Game.bPistols ? false : true); //30/07/04: Josh, handle the pistols only mode
- buy_secondary = (Game.bPistols ? true : false);
- buy_armor = false;
- buy_defusekit = false;
- bFirstOutOfSight = false;
- buy_grenade = false;
- buy_smokegrenade = false;
-
- buy_flashbang = 0;
- if (RANDOM_LONG(0, 100) < ipWalkWithKnife) {
- bWalkKnife = true;
- }
-
- if (UTIL_GetTeam(pEdict) == 1) {
- if (RANDOM_LONG(0, 100) < ipBuyDefuseKit) {
- buy_defusekit = true;
- }
- }
-
- if (RANDOM_LONG(0, 100) < ipBuyGrenade) {
- buy_grenade = true;
- }
-
- // 31.08.04 Frashman added Support for Smoke Grenade
- if (RANDOM_LONG(0, 100) < ipBuySmokeGren) {
- buy_smokegrenade = true;
- }
-
- if (RANDOM_LONG(0, 100) < ipBuyFlashBang) {
- buy_flashbang = 2;
-
- }
-
- if (RANDOM_LONG(0, 100) < 15 || Game.bPistols)
- buy_secondary = true;
-
- // ------------------------
- // HUD
- // ------------------------
- bHUD_C4_plantable = false; // Get's init'ed anyway... // BERKED
-
- // ------------------------
- // FLOATS
- // ------------------------
- f_strafe_speed = 0.0;
- f_max_speed = CVAR_GET_FLOAT("sv_maxspeed");
-
- // ------------------------
- // VECTORS
- // ------------------------
- prevOrigin = Vector(9999.0, 9999.0, 9999.0);
- lastSeenEnemyVector = Vector(0, 0, 0);
- vEar = Vector(9999, 9999, 9999);
-
- // ------------------------
- // CHAR
- // ------------------------
- arg1[0] = 0;
- arg2[0] = 0;
- arg3[0] = 0;
- memset(&(current_weapon), 0, sizeof(current_weapon));
- memset(&(m_rgAmmo), 0, sizeof(m_rgAmmo));
-
- rprint_trace("SpawnInit()", "END");
-}
-
-/******************************************************************************
- Function purpose: Initializes bot vars on new round
- ******************************************************************************/
-void cBot::NewRound() {
- rprint_trace("NewRound()", "START");
-
- // ------------------------
- // TIMERS
- // ------------------------
- fUpdateTime = gpGlobals->time;
- fLastRunPlayerMoveTime = gpGlobals->time;
- fCheckHostageStatusTimer = gpGlobals->time;
- fButtonTime = gpGlobals->time;
- fChatTime = gpGlobals->time + RANDOM_FLOAT(0.5, 5);
- fMemoryTime = gpGlobals->time;
- fDoRadio = gpGlobals->time;
- float freezeTimeCVAR = CVAR_GET_FLOAT("mp_freezetime");
- fNotStuckTime = gpGlobals->time + freezeTimeCVAR + 0.5f;
- f_shoot_wait_time = gpGlobals->time;
- f_goback_time = gpGlobals->time;
- f_may_jump_time = gpGlobals->time;
- f_defuse = gpGlobals->time;
- f_allow_keypress = gpGlobals->time;
- f_use_timer = gpGlobals->time;
- f_light_time = gpGlobals->time;
- f_sec_weapon = gpGlobals->time;
- f_prim_weapon = gpGlobals->time;
- f_gren_time = gpGlobals->time;
- f_walk_time = gpGlobals->time;
- f_hear_time = gpGlobals->time;
- freezeTime = gpGlobals->time - 1;
- f_cover_time = gpGlobals->time;
- f_c4_time = gpGlobals->time;
- f_update_weapon_time = gpGlobals->time;
- f_follow_time = gpGlobals->time;
- f_jump_time = 0.0;
- f_hold_duck = gpGlobals->time - 1;
- f_camp_time = gpGlobals->time;
- f_wait_time = gpGlobals->time;
- f_bot_see_enemy_time = gpGlobals->time;
- f_bot_find_enemy_time = gpGlobals->time;
- f_shoot_time = gpGlobals->time;
- fMoveToNodeTime = -1;
- nodeTimeIncreasedAmount = 0;
- distanceMovedTimer = gpGlobals->time;
- distanceMoved = 0;
- fBlindedTime = gpGlobals->time;
- f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.1, 0.9);
- fWanderTime = gpGlobals->time;
- f_strafe_time = gpGlobals->time;
-
- // ------------------------
- // POINTERS
- // ------------------------
- pButtonEdict = NULL;
- pBotHostage = NULL;
- clearHostages();
- pEnemyEdict = NULL;
-
- // ------------------------
- // INTEGERS
- // ------------------------
- i_camp_style = 0;
- iPrimaryWeapon = -1;
- iSecondaryWeapon = -1;
- zoomed = ZOOM_NONE;
- bot_health = 0;
- prev_health = 0;
- bot_armor = 0;
-// bot_weapons = 0; // <- stefan: prevent from buying new stuff every round!
- console_nr = 0;
- pathIndex = -1;
- iGoalNode = -1;
- goalIndex = -1;
- iPreviousGoalNode = -1;
- iCloseNode = -1;
-
-
- // Smarter Stuck stuff
- iDuckTries = 0;
- iJumpTries = 0;
-
- if (RANDOM_LONG(0, 100) < ipFearRate)
- iPathFlags = PATH_DANGER;
- else
- iPathFlags = PATH_NONE;
-
- // ------------------------
- // BOOLEANS
- // ------------------------
-
- // chat
- memset(chChatSentence, 0, sizeof(chChatSentence));
-
- vip = UTIL_IsVip(pEdict);
-
- // Every round consider
- bWalkKnife = false;
-
- if (RANDOM_LONG(0, 100) < ipWalkWithKnife)
- bWalkKnife = true;
-
- // Buying
- buy_ammo_primary = true;
- buy_ammo_secondary = true;
- buy_primary = (Game.bPistols ? false : true);
- buy_grenade = false;
- buy_smokegrenade = false;
- buy_flashbang = 0;
- buy_secondary = (Game.bPistols ? true : false);
- buy_armor = false;
- buy_defusekit = false;
-
- if (UTIL_GetTeam(pEdict) == 1)
- if (RANDOM_LONG(0, 100) < ipBuyDefuseKit)
- buy_defusekit = true;
-
- if (RANDOM_LONG(0, 100) < ipBuyArmour)
- buy_armor = true;
-
- if (RANDOM_LONG(0, 100) < ipBuyGrenade)
- buy_grenade = true;
-
- if (RANDOM_LONG(0, 100) < ipBuySmokeGren)
- buy_smokegrenade = true;
-
- if (RANDOM_LONG(0, 100) < ipBuyFlashBang)
- buy_flashbang = 2;
-
-
- bFirstOutOfSight = false;
-
-
- f_strafe_speed = 0.0;
-
- // ------------------------
- // VECTORS
- // ------------------------
- prevOrigin = Vector(9999.0, 9999.0, 9999.0);
- lastSeenEnemyVector = Vector(0, 0, 0);
- vEar = Vector(9999, 9999, 9999);
-
- // ------------------------
- // CHAR
- // ------------------------
- arg1[0] = 0;
- arg2[0] = 0;
- arg3[0] = 0;
-
- // initalize a few other stuff
- NodeMachine.path_clear(iBotIndex);
- iPathFlags = PATH_NONE;
-
- played_rounds++;
-
- // hello dudes
- if (played_rounds == 1) {
- // do some chatting
- if (RANDOM_LONG(0, 100) < (ipChatRate + 10)) {
- // we should say something now?
- int iMax = -1;
-
- for (int tc = 0; tc < 50; tc++) {
- if (ChatEngine.ReplyBlock[98].sentence[tc][0] != '\0')
- iMax++;
- }
-
- int the_c = RANDOM_LONG(0, iMax);
-
- if (the_c > -1 && iMax > -1) {
- char chSentence[80];
- memset(chSentence, 0, sizeof(chSentence));
- sprintf(chSentence, "%s ",
- ChatEngine.ReplyBlock[98].sentence[the_c]);
- PrepareChat(chSentence);
- }
- }
- }
-
- clearHostages();
- clearHostageToRescueTarget();
-
- rprint("NewRound", "Initialization new round finished");
-}
-
-/******************************************************************************
- Function purpose: Returns a random chat sentence and stores it into 'sentence'
- ******************************************************************************/
-void cBot::PrepareChat(char sentence[128]) {
- if (Game.iProducedSentences <= Game.iMaxSentences) {
- // makes bot chat away
- fChatTime = gpGlobals->time + RANDOM_FLOAT(0.1, 2.0);
- strcpy(chChatSentence, sentence); // copy this
- Game.iProducedSentences++;
- }
-}
-
-/******************************************************************************
- Function purpose: Return reaction time based upon skill
- ******************************************************************************/
-float cBot::ReactionTime(int iSkill) {
- float time = RANDOM_FLOAT(fpMinReactTime, fpMaxReactTime);
- if (Game.messageVerbosity > 1) {
- char msg[255];
- sprintf(msg, "minReactTime %f, maxReactTime %f, skill %d, results into %f", fpMinReactTime, fpMaxReactTime, iSkill, time);
- rprint_trace("ReactionTime()", msg);
- }
- return time;
-}
-
-/******************************************************************************
- Function purpose: Finds a (new) enemy
- ******************************************************************************/
-int cBot::FindEnemy() {
- // When on ladder, do not search for enemies
- if (isOnLadder())
- return -1;
-
- // When blinded we cannot search for enemies
- if (fBlindedTime > gpGlobals->time)
- return -1;
- float fNearestDistance = 9999; // Nearest distance
- edict_t *pNewEnemy = NULL; // New enemy found
-
- // SEARCH PLAYERS FOR ENEMIES
- for (int i = 1; i <= gpGlobals->maxClients; i++) {
- edict_t *pPlayer = INDEXENT(i);
-
- // skip invalid players and skip self (i.e. this bot)
- if ((pPlayer) && (!pPlayer->free) && (pPlayer != pEdict)) {
-
- // skip this player if not alive (i.e. dead or dying)
- if (!IsAlive(pPlayer))
- continue;
-
- Vector vVecEnd = pPlayer->v.origin + pPlayer->v.view_ofs;
-
- // if bot can see the player...
- if (FInViewCone(&vVecEnd, pEdict) && FVisible(vVecEnd, pEdict)) {
- int player_team = UTIL_GetTeam(pPlayer);
- int bot_team = UTIL_GetTeam(pEdict);
- if (player_team == bot_team)
- continue; // do not target teammates
-
- // Its not a friend, track enemy
- float fDistance =
- (pPlayer->v.origin - pEdict->v.origin).Length();
- bool bCanSee = true;
-
- // The further away, the less chance we see this enemy
- //if (RANDOM_FLOAT(0,1.0) < (fDistance/4096))
- // bCanSee=false;
- if (CarryWeaponType() == SNIPER)
- bCanSee = true;
- if (fDistance < fNearestDistance && bCanSee) {
- fNearestDistance = fDistance;
- pNewEnemy = pPlayer;
- }
- continue;
- }
- } // valid player
- } // FOR
-
- // We found a new enemy & the new enemy is different then previous pointer
- if (pNewEnemy && pNewEnemy != pEnemyEdict) {
- int iCurrentNode = determineCurrentNode();
-
- // Add 'contact' data
- if (iCurrentNode > -1) {
- NodeMachine.contact(iCurrentNode, UTIL_GetTeam(pEdict));
- }
-
- // We have a reaction time to this new enemy
- rememberEnemyFound();
- f_shoot_time = gpGlobals->time + ReactionTime(bot_skill);
- pEnemyEdict = pNewEnemy; // Update pointer
-
- // We did not have an enemy before
- if (pEnemyEdict == NULL) {
- rprint_trace("FindEnemy()", "Found new enemy");
-
- // RADIO: When we found a NEW enemy but NOT via a friend
- if (FUNC_DoRadio(this)) {
- UTIL_BotRadioMessage(this, 3, "2", "");
- }
-
- // We found a new enemy
- return 0;
- } else {
- // we found an enemy that is newer/more dangerous then previous
- rprint_trace("FindEnemy()", "Found 'newer' enemy");
- return 3;
- }
- }
-
- // nothing found
- return -1; // return result
-}
-
-void cBot::rememberEnemyFound() {
- f_bot_find_enemy_time = gpGlobals->time + REMEMBER_ENEMY_TIME;
-}
-
-/******************************************************************************
- Function purpose: Sets vHead to aim at vector
- ******************************************************************************/
-void cBot::setHeadAiming(Vector vTarget) {
- vHead = vTarget;
-}
-
-/**
- * Returns true / false wether enemy is alive.
- * @return
- */
-bool cBot::isEnemyAlive() {
- return IsAlive(pEnemyEdict);
-}
-
-bool cBot::isSeeingEnemy() {
- if (!hasEnemy()) {
- this->rprint("canSeeEnemy called without having enemy?");
- return false;
- }
-
- if (isBlindedByFlashbang()) {
- return false;
- }
-
- Vector vBody = pEnemyEdict->v.origin;
- Vector vHead = pEnemyEdict->v.origin + pEnemyEdict->v.view_ofs;
-
- bool bodyInFOV = FInViewCone(&vBody, pEdict) && FVisible(vBody, pEdict);
- bool headInFOV = FInViewCone(&vHead, pEdict) && FVisible(vHead, pEdict);
- if (bodyInFOV || headInFOV) {
- return true;
- }
- return false;
-}
-
-/******************************************************************************
- Function purpose: Aims at enemy, only when valid. Based upon skill how it 'aims'
- ******************************************************************************/
-void cBot::AimAtEnemy() {
- if (!hasEnemy())
- return;
-
- // We cannot see our enemy? -> bail out
- if (isSeeingEnemy()) {
- setHeadAiming(lastSeenEnemyVector); // look at last known vector of enemy
- return;
- }
-
- // ------------------------ we can see enemy -------------------------
- float fDistance;
-
- // Distance to enemy
- fDistance = (pEnemyEdict->v.origin - pEdict->v.origin).Length() + 1; // +1 to make sure we never divide by zero
-
- // factor in distance, the further away the more deviation - which is based on skill
- int skillReversed = (10 - bot_skill) + 1;
- float fScale = 0.5 + (fDistance / (64 *
- skillReversed)); // a good skilled bot is less impacted by distance than a bad skilled bot
-
- if (CarryWeaponType() == SNIPER) fScale *= 0.80; // sniping improves aiming
-
- // Set target here
- Vector vTarget;
- if (bot_skill <= 1)
- vTarget = pEnemyEdict->v.origin + pEnemyEdict->v.view_ofs * RANDOM_FLOAT(-0.5, 1.1); // aim for the head
- else if (bot_skill > 1 && bot_skill < 4)
- vTarget = pEnemyEdict->v.origin +
- pEnemyEdict->v.view_ofs * RANDOM_FLOAT(-2.5, 2.5); // aim for the head more fuzzy
- else
- vTarget = pEnemyEdict->v.origin; // aim for body
-
- // Based upon how far, we make this fuzzy
- float fDx, fDy, fDz;
- fDx = fDy = fDz = ((bot_skill + 1) * fScale);
-
- // Example 1:
- // Super skilled bot (bot_skill 1), with enemy of 2048 units away. Results into:
- // skillReversed = (10 - 0 + 1) == 11
- // fScale = 2048 / (128 * 11) -> 2048 / 1408 => 1.454545
- // fd* = 0.5 + 1 * 1,95
-
- // Example 2, less skilled bot (skill = 3) same enemy
- // skillReversed = (10 - 3 + 1) == 8
- // fScale = 2048 / (128 * 8) -> 2048 / 1024 => 2
- // fd* = 3 * 2
-
- vTarget = vTarget + Vector(
- RANDOM_FLOAT(-fDx, fDx),
- RANDOM_FLOAT(-fDy, fDy),
- RANDOM_FLOAT(-fDz, fDz)
- );
-
- // Add Offset
- fDx = fpXOffset;
- fDy = fpYOffset;
- fDz = fpZOffset;
-
- // increase offset with personality x,y,z offsets randomly
- vTarget = vTarget + Vector(
- RANDOM_FLOAT(-fDx, fDx),
- RANDOM_FLOAT(-fDy, fDy),
- RANDOM_FLOAT(-fDz, fDz)
- );
-
- if (isHoldingGrenadeOrFlashbang()) {
- // aim a bit higher
- vTarget = vTarget + Vector(0, 0, 50);
- }
-
- setHeadAiming(vTarget);
-}
-
-bool cBot::isBlindedByFlashbang() const {
- return fBlindedTime > gpGlobals->time;
-}
-
-bool cBot::isHoldingGrenadeOrFlashbang() const {
- return current_weapon.iId == CS_WEAPON_HEGRENADE || current_weapon.iId == CS_WEAPON_FLASHBANG;
-}
-
-/******************************************************************************
- Function purpose: Perform fighting actions
- ******************************************************************************/
-void cBot::FightEnemy() {
- // We can see our enemy
- if (!isBlindedByFlashbang() && isSeeingEnemy()) {
-
- // GET OUT OF CAMP MODE
- if (f_camp_time > gpGlobals->time) {
- f_camp_time = gpGlobals->time;
- }
-
- // Next time our enemy gets out of sight, it will be the 'first' time
- // of all 'frame times'.
- bFirstOutOfSight = false;
-
- // Remember last seen enemy position
- lastSeenEnemyVector = pEnemyEdict->v.origin; // last seen enemy position
-
- // FIXME: Fix the darn zoom bug
- // zoom in with sniper gun
- if (CarryWeaponType() == SNIPER) {
- if (zoomed < ZOOM_TWICE && f_allow_keypress < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK2);
- f_allow_keypress = gpGlobals->time + 0.7;
- zoomed++;
-
- if (zoomed > ZOOM_TWICE)
- zoomed = ZOOM_NONE;
- }
- } else if (FUNC_BotHoldsZoomWeapon(this)) {
- if (zoomed < ZOOM_ONCE && f_allow_keypress < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK2);
- f_allow_keypress = gpGlobals->time + 0.7;
- zoomed++;
- }
- }
-
- // NOT blinded by flashbang, try to find cover?
- if (f_cover_time < gpGlobals->time) {
- // COVER: Not taking cover now, fight using fightstyles.
-
- // when vip, we always take cover.
- if (vip) {
- // Camp, take cover, etc.
- BOT_DecideTakeCover(this);
-
- if (FUNC_DoRadio(this)) {
- UTIL_BotRadioMessage(this, 3, "3", ""); // need backup
- }
- } else {
- // DECIDE: Should we take cover or not.
- if (FUNC_ShouldTakeCover(this)) {
- FindCover();
- }
- }
- } else {
-
- }
-
- // Keep timer updated for enemy
- f_bot_find_enemy_time = gpGlobals->time + REMEMBER_ENEMY_TIME;
- }
- else // ---- CANNOT SEE ENEMY
- {
- if (f_bot_find_enemy_time < gpGlobals->time) {
- pEnemyEdict = NULL;
- lastSeenEnemyVector = Vector(0, 0, 0);
- rprint_trace("FightEnemy()", "Lost enemy out of sight, forgetting path and goal");
- forgetPath();
- forgetGoal();
- } else {
-
- // When we have the enemy for the first time out of sight
- // we calculate a path to the last seen position
- if (!bFirstOutOfSight) {
- rprint_trace("FightEnemy()", "Enemy out of sight, calculating path towards it.");
- // Only change path when we update our information here
- int iGoal = NodeMachine.getClosestNode(lastSeenEnemyVector, NODE_ZONE, pEdict);
- if (iGoal > -1) {
- setGoalNode(iGoal);
- forgetPath();
- }
-
- bFirstOutOfSight = true;
- } else {
- if (!hasGoal()) {
- rprint("Enemy out of sight and no goal, forgetting enemy");
- forgetEnemy();
- }
- }
- }
- } // visible
-}
-
-void cBot::pickWeapon(int weaponId) {
- UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(weaponId));
- f_c4_time = gpGlobals->time - 1; // reset C4 timer data
- // give Counter-Strike time to switch weapon (animation, update state, etc)
- f_update_weapon_time = gpGlobals->time + 0.7;
-}
-
-bool cBot::ownsFavoritePrimaryWeapon() {
- return hasFavoritePrimaryWeaponPreference() && isOwningWeapon(ipFavoPriWeapon);
-}
-
-bool cBot::ownsFavoriteSecondaryWeapon() {
- return hasFavoriteSecondaryWeaponPreference() && isOwningWeapon(ipFavoSecWeapon);
-}
-
-/**
- * Returns true if bot has weapon (id) in possession
- * @param weaponId
- * @return
- */
-bool cBot::isOwningWeapon(int weaponId) {
- return bot_weapons & (1 << weaponId);
-}
-
-/**
- * Returns true if bot carries weapon right now
- * @param weaponId
- * @return
- */
-bool cBot::isHoldingWeapon(int weaponId) {
- return (current_weapon.iId == weaponId);
-}
-
-bool cBot::hasFavoritePrimaryWeaponPreference() {
- return ipFavoPriWeapon > -1;
-}
-
-bool cBot::hasFavoriteSecondaryWeaponPreference() {
- return ipFavoSecWeapon > -1;
-}
-
-bool cBot::canAfford(int price) {
- return this->bot_money > price;
-}
-
-/******************************************************************************
- Function purpose: Based upon several events pick the best weapon
- ******************************************************************************/
-void cBot::PickBestWeapon() {
- // does Timer allow to change weapon? (only when f_update_weapon_time < gpGlobals->time
- if (f_update_weapon_time > gpGlobals->time)
- return;
-
- // Distance to enemy
- float fDistance = func_distance(pEdict->v.origin, lastSeenEnemyVector);
-
- float knifeDistance = 300;
-
- // ----------------------------
- // In this function all we do is decide what weapon to pick
- // if we don't pick another weapon the current weapon is okay
- // ----------------------------
-
- // First we handle situations which are bad, no matter the distance
- // or any other circumstance.
-
- // BAD: Carrying C4 or knife
- if (CarryWeapon(CS_WEAPON_C4) || // carrying C4
- (CarryWeapon(CS_WEAPON_KNIFE) && fDistance > knifeDistance)) { // carrying knife and too far
- if (hasPrimaryWeaponEquiped()) {
- pickWeapon(iPrimaryWeapon);
- return;
- } else if (hasSecondaryWeaponEquiped()) {
- pickWeapon(iSecondaryWeapon);
- return;
- }
- }
-
- // At this point we do not update weapon information. And we did not 'switch back' to primary / secondary
- if (hasEnemy() && !isSeeingEnemy()) {
- // decision to pull HE grenade
- if (isOwningWeapon(CS_WEAPON_HEGRENADE) && // we have a grenade
- func_distance(pEdict->v.origin, lastSeenEnemyVector) < 900 && // we are close
- func_distance(pEdict->v.origin, lastSeenEnemyVector) > 200 && // but not to close
- RANDOM_LONG(0, 100) < 10 && // only randomly we pick a grenade in the heat of the battle
- current_weapon.iId != CS_WEAPON_HEGRENADE && current_weapon.iId != CS_WEAPON_FLASHBANG &&
- f_gren_time + 15 < gpGlobals->time) // and dont hold it yet
- {
- UTIL_SelectItem(pEdict, "weapon_hegrenade"); // select grenade
- f_wait_time = gpGlobals->time + 1; // wait 1 second (stand still 1 sec)
- f_gren_time =
- gpGlobals->time + (1.0 + RANDOM_FLOAT(0.5, 1.5)); // and determine how long we should hold it
- zoomed = ZOOM_NONE; // Counter-Strike resets zooming when choosing another weapon
- return;
- }
- // OR we pull a flashbang?
- if (isOwningWeapon(CS_WEAPON_FLASHBANG) && // we have a grenade
- func_distance(pEdict->v.origin, lastSeenEnemyVector) < 200 && // we are close
- func_distance(pEdict->v.origin, lastSeenEnemyVector) > 300 && // but not to close
- RANDOM_LONG(0, 100) < 15 && // only randomly we pick a grenade in the heat of the battle
- current_weapon.iId != CS_WEAPON_FLASHBANG && current_weapon.iId != CS_WEAPON_HEGRENADE &&
- f_gren_time + 15 < gpGlobals->time) // and dont hold it yet
- {
- UTIL_SelectItem(pEdict, "weapon_flashbang"); // select grenade
- f_wait_time = gpGlobals->time + 1; // wait 1 second (stand still 1 sec)
- f_gren_time =
- gpGlobals->time + (1.0 + RANDOM_FLOAT(0.5, 1.5)); // and determine how long we should hold it
- zoomed = ZOOM_NONE; // Counter-Strike resets zooming when choosing another weapon
- return;
- }
- }
-
- // When we are here, we did not decide to switch to grenade/flashbang. Now we look
- // if the bot has to reload or switch weapon based upon ammo.
-
- // ----------------------------------------
- // More complex bad things that can happen:
- // ----------------------------------------
- int iTotalAmmo = current_weapon.iAmmo1;
- int iCurrentAmmo = current_weapon.iClip;
-
- //char msg[80];
- //sprintf(msg, "BOT: ICLIP %d, TOTALAMMO %d\n", iCurrentAmmo, iTotalAmmo);
-
- // Clip is out of ammo
- if (iCurrentAmmo < 1
- && (CarryWeaponType() == PRIMARY || CarryWeaponType() == SECONDARY)) {
- // Camp, take cover, etc.
- BOT_DecideTakeCover(this);
-
- // We still have ammo!
- if (iTotalAmmo > 0) {
- UTIL_BotPressKey(this, IN_RELOAD);
- f_update_weapon_time = gpGlobals->time + 0.7; // update timer
- return;
- } else {
- // Thanks to dstruct2k for easy ctrl-c/v, i optimized the code
- // a bit though. Btw, distance 600 is too far for slashing :)
-
- // at here the bot does not have ammo of the current weapon, so
- // switch to another weapon.
- if (iPrimaryWeapon > -1 && // we have a primary
- current_weapon.iId != iPrimaryWeapon && // that's not the current, empty gun
- func_distance(pEdict->v.origin, lastSeenEnemyVector) > 300) // and we are not close enough to knife
- {
- // select primary weapon
- UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iPrimaryWeapon)); // select the primary
- return;
- } else {
-
- if (iSecondaryWeapon > -1 && current_weapon.iId != iSecondaryWeapon &&
- // that's not the current, empty gun
- func_distance(pEdict->v.origin, lastSeenEnemyVector) > 300) // and we are not close enough to knife
- {
- UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iSecondaryWeapon)); // select the secondary
- return;
- } else {
- if (isOwningWeapon(CS_WEAPON_KNIFE) && // we have a knife (for non-knife maps)
- !isHoldingWeapon(CS_WEAPON_KNIFE)) // but we do not carry it
- {
- UTIL_SelectItem(pEdict, "weapon_knife");
- return;
- }
- }
- } // end if
- } // no ammo
- }
-}
-
-/******************************************************************************
- Function purpose: Fire weapon (burst; or do not fire when not allowed)
- ******************************************************************************/
-void cBot::FireWeapon() {
- // We may not shoot!
- if (f_shoot_time > gpGlobals->time ||
- f_update_weapon_time > gpGlobals->time)
- return;
-
- if (!isSeeingEnemy()) {
- return;
- }
-
- // ------------------------------------------------------------
- float fDistance = 50;
-
- if (hasEnemy()) {
- fDistance = func_distance(pEdict->v.origin, pEnemyEdict->v.origin);
- }
-
- // Depending on weapon type
- if (CarryWeaponType() == SECONDARY) {
- // We may shoot, use shooting rate.
- // TODO TODO TODO; Add shooting rates in BUYTABLE.INI
-
- if (f_sec_weapon < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK);
- f_sec_weapon = gpGlobals->time + RANDOM_FLOAT(0.05, 0.2);
- }
-
- } else if (CarryWeaponType() == PRIMARY) {
- // We may shoot, use shooting rate.
- // TODO TODO TODO: Add shooting rates in BUYTABLE.INI
- if (f_prim_weapon < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
- // All other weapons, the more distance, the more time we add to holding weapon
- if (f_shoot_wait_time < gpGlobals->time) {
- // AK, COLT, STEYR AUG, only when enough skill!
- if ((CarryWeapon(CS_WEAPON_AK47)
- || CarryWeapon(CS_WEAPON_M4A1)
- || CarryWeapon(CS_WEAPON_AUG)) && (bot_skill < 3)) {
- float f_burst = 0.1;
- f_burst = (2048 / fDistance) + 0.1;
- if (f_burst < 0.1)
- f_burst = 0.1;
- if (f_burst > 0.4)
- f_burst = 0.4;
-
- // CS 1.6 less burst
- if (counterstrike == 1)
- if (f_burst > 0.3)
- f_burst = 0.3;
-
- f_prim_weapon = gpGlobals->time + f_burst;
-
- f_shoot_wait_time = gpGlobals->time + (f_burst * 3);
- } else // other weapons
- {
- float f_burst = 0.1;
- if (fDistance > 300 && bot_skill < 6) {
- f_burst = ((fDistance - 300) / 550);
- if (f_burst < 0.1)
- f_burst = 0.0;
- if (f_burst > 0.7)
- f_burst = 0.7;
-
- // CS 1.6 less burst
- if (counterstrike == 1)
- if (f_burst > 0.2)
- f_burst = 0.2;
- if (f_prim_weapon < gpGlobals->time)
- f_prim_weapon = gpGlobals->time + f_burst;
- }
- f_shoot_wait_time =
- gpGlobals->time + f_burst + RANDOM_FLOAT(0.2, 0.7);
- }
- }
- } // give the bot alteast 0.3 seconds to fire its weapon
- } // PRIMARY
- else if (CarryWeaponType() == GRENADE) {
- if (f_gren_time > gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
- setMoveSpeed(f_max_speed / 2);
-
- // Set new goal when holding flashbang!
- if (current_weapon.iId == CS_WEAPON_FLASHBANG) {
-
- //tonode ?
- // COVER: Take cover, using tracelines all the time!
- FindCover();
- }
- } else if (f_gren_time + 0.5 < gpGlobals->time) {
- // NOTE: Should not happen, a bot cannot 'forget' this...
- f_gren_time = gpGlobals->time + 1;
- }
- } // GRENADE
- else if (CarryWeaponType() == KNIFE) {
- setMoveSpeed(f_max_speed);
- UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
- } // KNIFE
- else if (CarryWeaponType() == SNIPER) {
- setMoveSpeed(f_max_speed / 2);
- UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
- f_shoot_time = gpGlobals->time + 1.0;
- } // SNIPER
- else if (CarryWeaponType() == SHIELD) {
- if (fDistance > 550) {
- if (hasShieldDrawn()) {
- // when the enemy is far away, we keep it
- } else {
- // draw shield!
- UTIL_BotPressKey(this, IN_ATTACK2); // secondary attack makes shield draw
- f_allow_keypress = gpGlobals->time + 0.7;
- }
- } else {
- // get weapon here.
- if (hasShieldDrawn() && f_allow_keypress < gpGlobals->time) {
- rblog
- ("BOT: Enemy is close enough, i should withdraw shield to attack this enemy\n");
- UTIL_BotPressKey(this, IN_ATTACK2);
- f_allow_keypress = gpGlobals->time + 0.7;
- }
- }
- } else {
- // debug print
- REALBOT_PRINT(this, "FireWeapon()", "Unknown weapon");
- }
-}
-
-/******************************************************************************
- Function purpose: The combat brain of the bot ( called by Think() )
- ******************************************************************************/
-void cBot::Combat() {
- if (!hasEnemy()) {
- rprint("Unexpected call to Combat because bot has no enemy!");
- return;
- }
-
- // Bot is on ladder
- if (isOnLadder()) {
- // TODO: Bot fights when on ladder
- return;
- }
-
- // We have an enemy and it is now dead
- if (!isEnemyAlive()) {
-
- // radio (Enemy down)
- if (FUNC_DoRadio(this)) {
- UTIL_BotRadioMessage(this, 3, "9", "");
- }
-
- // get bot pointer
- cBot *checkpointer = UTIL_GetBotPointer(pEnemyEdict);
-
- // This bot killed a human; adjust skill when 'autoskill' is on.
- if (checkpointer == NULL) {
-
- // increase bot_skill value when autoskill enabled (making bot weaker)
- if (autoskill && bot_skill < 10) {
- bot_skill++;
- }
-
- if (Game.iDeathsBroadcasting != BROADCAST_DEATHS_NONE) {
- // This is a human, we will tell this human he has been killed
- // by a bot.
- int r = RANDOM_LONG(150, 255);
- int g = RANDOM_LONG(30, 155);
- int b = RANDOM_LONG(30, 155);
- char msg[128];
- if (Game.iDeathsBroadcasting == BROADCAST_DEATHS_FULL) {
- sprintf(msg, "A RealBot has killed you!\n\nName:%s\nSkill:%d\n", name, bot_skill);
- } else {
- sprintf(msg, "A RealBot named %s has killed you!", name);
- }
-
- HUD_DrawString(r, g, b, msg, pEnemyEdict);
- }
- }
-
- // clear the pointer for this and other bots that might have the same pEnemyEdict
- FUNC_ClearEnemyPointer(pEnemyEdict);
-
- // from here react after kill...
- forgetGoal();
- forgetPath();
-
- if (lastSeenEnemyVector != Vector(0, 0, 0)) {
- vHead = lastSeenEnemyVector;
- }
-
- lastSeenEnemyVector = Vector(0, 0, 0);
-
- // random waiting
- f_wait_time = gpGlobals->time + (1 + RANDOM_FLOAT(0.0, 0.4));
-
- // keep on walking when afraid (perhaps there are more enemies)
- if (RANDOM_LONG(0, 100) < ipFearRate)
- f_walk_time = gpGlobals->time + (1 + RANDOM_FLOAT(0.0, 2.0));
-
- InteractWithPlayers(); // check any new enemy here immediately
-
- return;
- }
-
- // ----------- combat
-
- // STEP 1: Pick best weapon to fight with
- PickBestWeapon();
-
- // STEP 2: Decide how to move to make us a harder target
- FightEnemy();
-
- // STEP 3: Aim at enemy (skill-based)
- AimAtEnemy();
-
- // STEP 4: Fire!
- FireWeapon();
-}
-
-/******************************************************************************
- Function purpose: Find cover
- Note: Using tracelines to get a cover node.
- ******************************************************************************/
-void cBot::FindCover() {
- TraceResult tr;
- Vector dest = lastSeenEnemyVector;
- // Vector start = pEdict->v.origin;
- // Vector end;
- Vector cover_vect = Vector(9999, 9999, 9999);
-
- // When vector is visible, then look from that vector to the threat, if then NOT
- // Visible, then its cover.
- Vector v_src, v_right, v_left;
-
- // TraceLines in 2 directions to find which way to go...
- UTIL_MakeVectors(pEdict->v.v_angle);
- v_src = pEdict->v.origin + pEdict->v.view_ofs;
- v_right = v_src + gpGlobals->v_right * 90;
- v_left = v_src + gpGlobals->v_right * -90;
-
- // We have now our first 'left' and 'right'
-
- // First check the right..
- UTIL_TraceLine(v_src, v_right, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
-
- if (tr.flFraction >= 1.0) {
- // We can see it
- // Now trace from that vector to our threat
- UTIL_TraceLine(v_right, dest, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
-
- // If this is blocking.. then its a good wpt
- if (tr.flFraction < 1.0)
- cover_vect = v_right;
- }
-
- // Now check at the left
- UTIL_TraceLine(v_src, v_left, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
-
- if (tr.flFraction >= 1.0) {
- // We can see it
- // Now trace from that vector to our threat
- UTIL_TraceLine(v_left, dest, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
-
- // If this is blocking.. then its a good wpt
- if (tr.flFraction < 1.0) {
- // If we already found a wpt, then randomly pick this one
- if (cover_vect != Vector(9999, 9999, 9999)) {
- if (RANDOM_LONG(0, 100) < 50)
- cover_vect = v_left;
- } else
- cover_vect = v_left;
- }
- }
- // Now update the V_left and V_right and do the checks again.
- // Vector old_right = v_right;
- // Vector old_left = v_left;
- v_right = v_src + gpGlobals->v_right * 180;
- v_left = v_src + gpGlobals->v_right * -180;
-
- // Now check at the right again
- UTIL_TraceLine(v_src, v_right, dont_ignore_monsters,
- pEdict->v.pContainingEntity, &tr);
-
- if (tr.flFraction >= 1.0) {
- // We can see it
- // Now trace from that vector to our threat
- UTIL_TraceLine(v_right, dest, dont_ignore_monsters,
- pEdict->v.pContainingEntity, &tr);
-
- // If this is blocking.. then its a good wpt
- if (tr.flFraction < 1.0) {
- // If we already found a wpt, then randomly pick this one
- if (cover_vect != Vector(9999, 9999, 9999)) {
- if (RANDOM_LONG(0, 100) < 50)
- cover_vect = v_right;
- } else
- cover_vect = v_right;
- }
- }
-
- // Now check at the left
- UTIL_TraceLine(v_src, v_left, dont_ignore_monsters,
- pEdict->v.pContainingEntity, &tr);
- if (tr.flFraction >= 1.0) {
- // We can see it
- // Now trace from that vector to our threat
- UTIL_TraceLine(v_left, dest, dont_ignore_monsters,
- pEdict->v.pContainingEntity, &tr);
-
- // If this is blocking.. then its a good wpt
- if (tr.flFraction < 1.0) {
- // If we already found a wpt, then randomly pick this one
- if (cover_vect != Vector(9999, 9999, 9999)) {
- if (RANDOM_LONG(0, 100) < 50)
- cover_vect = v_left;
- } else
- cover_vect = v_left;
- }
- }
-
- int iNodeEnemy = NodeMachine.getClosestNode(pEnemyEdict->v.origin, 60, pEnemyEdict);
- int iNodeFrom = NodeMachine.getClosestNode(pEdict->v.origin, NODE_ZONE, pEdict);
-
- // --------------
- // TEST TEST TEST
- // --------------
- int iCoverNode = NodeMachine.node_cover(iNodeFrom, iNodeEnemy, pEdict);
- bool bTakenCover = false;
-
- if (iCoverNode > -1) {
- rprint("FindCover()", "cover node found (node based)");
- setGoalNode(iCoverNode);
- forgetPath();
-
- // Calculate a path to this position and get the heck there.
- createPath(iCoverNode);
- f_cover_time = gpGlobals->time + 8;
- bTakenCover = true;
- } else {
-
- // --------------------------------------------------
- // If cover_vect is found, we find a node close to it
- // --------------------------------------------------
- if (cover_vect != Vector(9999, 9999, 9999)) {
- rprint("FindCover()", "cover node found (cover_vect based)");
- int iNodeCover = NodeMachine.getClosestNode(cover_vect, 60, pEdict);
- if (iNodeCover > -1) {
- setGoalNode(iNodeCover);
- forgetPath();
-
- // Calculate a path to this position and get the heck there.
- rprint("createPath -> find cover node");
- NodeMachine.createPath(iNodeFrom, iNodeCover, iBotIndex, this, PATH_NONE);
- f_cover_time = gpGlobals->time + 8;
- bTakenCover = true;
- }
- }
- }
-
- // when we have taken cover, and we are leader, command our team to get
- // into our position to cover area
- if (bTakenCover) {
- // do something...
- }
-
-} // FindCover()
-
-void cBot::InteractWithFriends() {
-
-
- // TODO TODO TODO; make this thing really work
- return;
-
- // We interact with our players in some way
- //
- // When a bot is camping, another bot can choose to say 'go go go' for example.
- //
- //
-
- for (int i = 1; i <= gpGlobals->maxClients; i++) {
-
- edict_t *pPlayer = INDEXENT(i);
-
- // skip invalid players and skip self (i.e. this bot)
- if ((pPlayer) && (!pPlayer->free) && (pPlayer != pEdict)) {
- // skip this player if not alive (i.e. dead or dying)
- if (!IsAlive(pPlayer))
- continue;
-
- // skip enemies
- if (UTIL_GetTeam(pPlayer) != UTIL_GetTeam(pEdict))
- continue;
-
- bool bCanSeePlayer = false;
- bool bClose = false;
-
- Vector vVecEnd = pPlayer->v.origin + pPlayer->v.view_ofs;
-
- if (func_distance(pPlayer->v.origin, pEdict->v.origin) < 450)
- bClose = true;
-
- if (FInViewCone(&vVecEnd, pEdict) && FVisible(vVecEnd, pEdict))
- bCanSeePlayer = true;
-
- // there are tons of cases
- cBot *pBotPointer = UTIL_GetBotPointer(pPlayer);
-
- // It is a fellow bot
- if (pBotPointer != NULL) {
- if (bClose) {
- if (pBotPointer->f_camp_time > gpGlobals->time
- && pBotPointer->f_camp_time - 10 < gpGlobals->time
- && pBotPointer->pEnemyEdict == NULL
- && (RANDOM_LONG(0, 100) < ipCampRate
- && FUNC_DoRadio(this))) {
- // issue go go go
- UTIL_BotRadioMessage(this, 2, "1", ""); // go go go!
- }
- }
-
- if (bCanSeePlayer) {}
- } else // it is a teammate, but it is human (or a different bot)
- {
- // when firing
-
- }
-
- // any player:
- if (bClose) {
- // some one is close, need backup?
- if (RANDOM_LONG(0, 100) < ipFearRate && pEnemyEdict != NULL)
- if (FUNC_DoRadio(this)) {
- UTIL_BotRadioMessage(this, 3, "3", ""); // need backup
- }
- }
- }
- }
-
-}
-
-// BOT: Interact with Players ('find enemy, and how to react upon them')
-void cBot::InteractWithPlayers() {
-
- // friends are important, we are a team dudes!
- InteractWithFriends();
-
- int result = FindEnemy();
-
- // -------------------------------
- // RESULT < 0; NO ENEMY FOUND
- // -------------------------------
-
- // No enemy found, unzoom
- if (result < 0) {
- // Keep f_prim_weapon updated, else we do burst immidiatly
- if (CarryWeaponType() == SNIPER) {
-
- // Unzoom (for sniper guns)
- if (zoomed > ZOOM_NONE && f_allow_keypress < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK2);
- f_allow_keypress = gpGlobals->time + 0.7;
- zoomed++;
- }
- if (zoomed > ZOOM_TWICE)
- zoomed = ZOOM_NONE;
- } else if (FUNC_BotHoldsZoomWeapon(this)) {
-
- // Unzoom (for other guns with only 1 zoom)
- if (zoomed > ZOOM_NONE && f_allow_keypress < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK2);
- f_allow_keypress = gpGlobals->time + 0.7;
- zoomed = ZOOM_NONE;
- }
- } else {
-
- // For any weapon that has a silencer (the colt for example), use it if we want that.
- if (isHoldingWeapon(CS_WEAPON_M4A1))
- if (bot_use_special == 0 && zoomed == ZOOM_NONE
- && f_allow_keypress < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK2);
- zoomed = ZOOM_ONCE;
- }
- }
- }
- // ------------------------------------------------
- // RESULT > -1 ; ENEMY FOUND / NO SPECIFIC REACTION
- // ------------------------------------------------
- if (result > -1 && result < 4) {
-
- // VIP: When we found an enemy, we have a problem.
- if (vip) {
-
- // We do not forget our enemy, but we will try to get the heck out of here.
- // TODO TODO TODO: code something here?
- }
- // Whenever we hold a knife, get our primary weapon
- if (CarryWeapon(CS_WEAPON_KNIFE)) {
-
- // switch back to primary
- if (iPrimaryWeapon > -1)
- UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iPrimaryWeapon));
-
- else // pick secondary
- UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iSecondaryWeapon));
-
- f_update_weapon_time = gpGlobals->time + 0.7;
- }
- }
- // ------------------------------------------------
- // RESULT = 1 ; ENEMY FOUND, VIA FRIEND!
- // ------------------------------------------------
-
- // When we have found an enemy via a friend, we simply build a path to it.
- if (result == 1) {
-
- /*
- f_prim_weapon = gpGlobals->time;
-
- // DECIDE:
- // Do we go into battle, or do we wait first a few seconds?
-
- // HEALTH: The less we have, the more we want to wait
- int vHealth = 100-bot_health;
-
- // CAMP: The more we want to camp, the more we want to wait.
- int vCamp = ipCampRate;
-
- if (RANDOM_LONG(0,200) < (vHealth+vCamp))
- {
- // depending on how much we want, the longer we wait
- float fWaitTime = ((200/(vHealth+vCamp))*5);
- f_wait_time = gpGlobals->time + fWaitTime;
-
- // TODO TODO TODO; we might not even want to wait, but also take 'cover'?
- }
-
- // INITIALIZATION:
- int iGoal = NodeMachine.getCloseNode(pBotEnemy->v.origin, NODE_ZONE, pBotEnemy);
- if (iGoal > -1)
- {
- iGoalNode = iGoal;
- pathNodeIndex = -1;
- }
- */
- }
- // ------------------------------------------------
- // RESULT = 0 ; NEW ENEMY FOUND
- // ------------------------------------------------
- if (result == 0) {
- // First Encounter
- //f_prim_weapon = gpGlobals->time;
- if (CarryWeaponType() == SNIPER) {
- if (zoomed < ZOOM_TWICE && f_allow_keypress < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK2);
- f_allow_keypress = gpGlobals->time + 0.7;
- zoomed++;
- }
- }
-
- // INITIALIZATION:
- int iGoal = NodeMachine.getClosestNode(pEnemyEdict->v.origin, NODE_ZONE, pEnemyEdict);
- if (iGoal > -1) {
- rprint_trace("InteractWithPlayers()", "Found a new enemy, setting goal and forgetting path");
- setGoalNode(iGoal);
- forgetPath();
- }
-
- // Speed our enemy runs
- // int run_speed = FUNC_PlayerSpeed(pBot->pBotEnemy);
- // Distance between Us and Enemy.
- // float f_distance = func_distance(pBot->pEdict->v.origin,
- // pBot->pBotEnemy->v.origin);
-
- // Does our enemy (when a bot) has focus on us?
- bool focused = false;
- cBot *playerbot = UTIL_GetBotPointer(pEnemyEdict);
- if (playerbot) {
- if (playerbot->pEnemyEdict == pEdict)
- focused = true;
- } else // Its a human
- {
-
- // When we are in his 'sight' of 25 degrees , we are pretty
- // much focussed for a first encounter.
- if (FUNC_InFieldOfView
- (pEdict, (pEnemyEdict->v.origin - pEdict->v.origin)) < 25)
- focused = true;
- }
-
- /******************************
- At this moment we know:
- - The distance between us and enemy
- - The focus (are we targetted too?)
- - The speed of the enemy (running, standing still? etc)
- *******************************/
- } // We have a first encounter
-
- // ------------------------------------------------
- // RESULT = 3 ; NEWER ENEMY FOUND
- // ------------------------------------------------
- if (result == 3) {
- //
- // Newer enemy found, update goals and such, but thats all!
- //
-
- // INITIALIZATION:
- int iGoal = NodeMachine.getClosestNode(pEnemyEdict->v.origin, NODE_ZONE, pEnemyEdict);
-
- if (iGoal > -1) {
- rprint_trace("InteractWithPlayers()", "Found a *newer* enemy, so picking goal node to that");
- setGoalNode(iGoal);
- forgetPath();
- }
- }
-}
-
-// BOT: INTERACT WITH PLAYERS
-void cBot::JoinTeam() {
- if (mod_id != CSTRIKE_DLL) return;
- // When bot plays Counter-Strike (only Counter-Strike is supported)
-
- char c_team[32];
- char c_class[32];
-
- // Choose team first
- if (start_action == MSG_CS_TEAM_SELECT) {
- start_action = MSG_CS_IDLE; // switch back to idle
-
- // in case of bad state/input fall-back to 'pick one for me'
- if ((iTeam != 1) && (iTeam != 2) && (iTeam != 5)) {
- iTeam = 5;
- }
-
- // select the team the bot wishes to join...
- if (iTeam == 1) {
- strcpy(c_team, "1");
- } else if (iTeam == 2) {
- strcpy(c_team, "2");
- } else {
- strcpy(c_team, "5");
- }
-
- // choose
- FakeClientCommand(this->pEdict, "menuselect", c_team, NULL);
-
- return;
- }
-
- // counter terrorist menu, which class/outfit?
- if (start_action == MSG_CS_CT_SELECT) {
- start_action = MSG_CS_IDLE; // switch back to idle
-
- if ((bot_class < 1) || (bot_class > 4))
- bot_class = 5; // use random if invalid
-
- // Since cs 1.6 does not give us pretty random models
- // we do it ourselves
- if (bot_class == 5) {
- bot_class = RANDOM_LONG(1, 4);
- }
-
- // select the class the bot wishes to use...
- if (bot_class == 1)
- strcpy(c_class, "1");
- else if (bot_class == 2)
- strcpy(c_class, "2");
- else if (bot_class == 3)
- strcpy(c_class, "3");
- else if (bot_class == 4)
- strcpy(c_class, "4");
- else
- strcpy(c_class, "5"); // random
-
- FakeClientCommand(this->pEdict, "menuselect", c_class, NULL);
-
- // bot has now joined a team
- hasJoinedTeam = true;
-
- return;
- }
-
- // terrorist select
- if (start_action == MSG_CS_T_SELECT) {
- start_action = MSG_CS_IDLE; // switch back to idle
-
- if ((bot_class < 1) || (bot_class > 4))
- bot_class = 5; // use random if invalid
-
- // Since cs 1.6 does not give us pretty random models
- // we do it ourselves
- if (bot_class == 5)
- bot_class = RANDOM_LONG(1, 4);
-
- // select the class the bot wishes to use...
- if (bot_class == 1)
- strcpy(c_class, "1");
- else if (bot_class == 2)
- strcpy(c_class, "2");
- else if (bot_class == 3)
- strcpy(c_class, "3");
- else if (bot_class == 4)
- strcpy(c_class, "4");
- else
- strcpy(c_class, "5"); // random
-
- FakeClientCommand(this->pEdict, "menuselect", c_class, NULL);
-
- // bot has now joined the game (doesn't need to be started)
- hasJoinedTeam = true;
-
- return;
- }
-}
-
-int cBot::ReturnTurnedAngle(float speed, float current, float ideal) {
-
- // hope this fix the unnescesary turning of bots.
- // how? we save the values here, andc alculate the new value.
- // this part is copied from botchangeyaw/pitch so it SHOULD work :)
- float current_180; // current +/- 180 degrees
- float diff;
-
- // turn from the current v_angle pitch to the idealpitch by selecting
- // the quickest way to turn to face that direction
-
- // find the difference in the current and ideal angle
- diff = fabs(current - ideal);
-
- // check if the bot is already facing the idealpitch direction...
- if (diff <= 1.0)
- return (int) current; // return number of degrees turned
-
- // check if difference is less than the max degrees per turn
- if (diff < speed)
- speed = diff; // just need to turn a little bit (less than max)
-
- // here we have four cases, both angle positive, one positive and
- // the other negative, one negative and the other positive, or
- // both negative. handle each case separately...
- if ((current >= 0.0) && (ideal >= 0.0)) // both positive
- {
- if (current > ideal)
- current -= speed;
-
- else
- current += speed;
- } else if ((current >= 0.0) && (ideal < 0.0)) {
- current_180 = current - 180.0;
- if (current_180 > ideal)
- current += speed;
-
- else
- current -= speed;
- } else if ((current < 0) && (ideal >= 0)) {
- current_180 = current + 180;
- if (current_180 > ideal)
- current += speed;
-
- else
- current -= speed;
- } else // (current < 0) && (ideal < 0) both negative
- {
- if (current > ideal)
- current -= speed;
-
- else
- current += speed;
- }
-
- // check for wrap around of angle...
- if (current > 180)
- current -= 360;
- if (current < -180)
- current += 360;
- return (int) current; // return what it should be
-}
-
-// BOT: sub-function (DEFUSE) for ACT()
-bool cBot::Defuse() {
- if (!isCounterTerrorist()) // non-Counter-Terrorists have no business here
- return false;
-
- // this bot is defusing
- if (shouldActWithC4() && keyPressed(IN_USE)) {
- setTimeToMoveToNode(3);
- return true;
- }
-
- // What i do, i search for the c4 timer, store its origin and check
- // if this bot is close. If so, the bot should be defusing the bomb
- // if the timers are set. The above check makes sure that no other
- // bot will be defusing the bomb.
- edict_t *pent = NULL;
- bool c4Found = false;
- while ((pent = UTIL_FindEntityByClassname(pent, "grenade")) != NULL) {
- if (UTIL_GetGrenadeType(pent) == 4) { // It is a C4
- c4Found = true;
- break;
- }
- }
-
- if (!c4Found) {
- rprint_normal("Defuse()", "No C4 planted yet");
- return false;
- }
-
- rprint_normal("Defuse()", "C4 is planted!");
-
- // A c4 has been found, oh dear.
- // Remember, pent=c4 now!
-
- // Calculate the distance between our position to the c4
- Vector vC4 = pent->v.origin;
- float distance = func_distance(pEdict->v.origin, vC4);
-
- // can see C4
- bool canSeeC4 = canSeeVector(vC4);
-
- if (!canSeeC4) {
- rprint_trace("Defuse()", "Cannot see planted C4 - bailing");
- return false;
- }
-
- // it can be seen, so it has been discovered
- if (!Game.isPlantedC4Discovered()) {
- this->rprint_trace("Defuse()", "C4 is discovered, remembering its coordinates");
- Game.vPlantedC4 = vC4;
- }
-
- // We can do 2 things now
- // - If we are not close, we check if we can walk to it, and if so we face to the c4
- // - If we are close, we face it and (begin) defuse the bomb.
- int distanceForC4ToBeInReach = 70;
- if (distance < distanceForC4ToBeInReach) {
- vHead = vC4;
- vBody = vC4;
-
- setTimeToMoveToNode(3); // we are going to do non-path-follow stuff, so keep timer updated
- int angle_to_c4 = FUNC_InFieldOfView(pEdict, (vC4 - pEdict->v.origin));
-
- // if defusion timer has not been set (ie, the bot is not yet going to defuse the bomb)
- if (f_defuse < gpGlobals->time && angle_to_c4 < 35) {
- this->rprint("Defuse()", "I'll start defusing the bomb");
- // when we are 'about to' defuse, we simply set the timers
- f_defuse = gpGlobals->time + 90; // hold as long as you can
- f_allow_keypress = gpGlobals->time + 1.5; // And stop any key pressing the first second
- // ABOUT TO DEFUSE BOMB
- }
-
- // Defusion timer is set and c4 is within vision
- if (f_defuse > gpGlobals->time && angle_to_c4 < 35) {
- this->rprint("Defuse()", "I'm defusing the bomb");
- setMoveSpeed(0.0);
- f_c4_time = gpGlobals->time + 6;
- UTIL_BotPressKey(this, IN_DUCK);
-
- if (func_distance(pEdict->v.origin, vC4) > 50
- && f_allow_keypress + 0.5 > gpGlobals->time) {
- setMoveSpeed(f_max_speed / 2);
- }
- }
-
- if (f_allow_keypress < gpGlobals->time && f_defuse > gpGlobals->time) {
- UTIL_BotPressKey(this, IN_USE);
- }
-
- } else {
- rprint_trace("Defuse()", "I can see C4, but it is out of reach.");
- int iGoalNode = NodeMachine.getClosestNode(vC4, distanceForC4ToBeInReach, NULL);
- if (iGoalNode < 0) {
- rprint_normal("Defuse()", "No node close, so just look at it/body face at it and move towards it.");
- vHead = vC4;
- vBody = vC4;
- }
-
- if (iGoalNode > -1) {
- // we are not heading for this goal yet
- if (iGoalNode > -1 && getGoalNode() != iGoalNode) {
- rprint_normal("Defuse()", "I don't have a goal towards the C4, overriding it now to C4 destination!");
- forgetPath();
- forgetGoal();
- setGoalNode(iGoalNode);
- } else {
- rprint_normal("Defuse()", "I already have a goal towards the C4!");
- }
- } else {
- rprint_normal("Defuse()", "C4 is somewhere without a close node.");
- }
- setMoveSpeed(f_max_speed);
- } // distance < ...
-
- // we can see the bomb, and we act upon it
- return true;
-}
-
-int cBot::keyPressed(int key) const {
- return pEdict->v.button & key;
-}
-
-// BOT: Act
-void cBot::Act() {
- // chat
- if (fChatTime < gpGlobals->time) {
- if (chChatSentence[0] != '\0') {
- UTIL_SayTextBot(chChatSentence, this);
- memset(chChatSentence, 0, sizeof(chChatSentence));
- }
- }
-
- // camp
- if (f_camp_time > gpGlobals->time) {
- // When camping we duck and we don't move
- // todo, camping can be done standing too, but this does not look 'cool' atm.
- UTIL_BotPressKey(this, IN_DUCK);
-
- setMoveSpeed(0.0); // do not move
- PickBestWeapon(); // pick weapon, do not stare with knife
-
- // when dropped C4 and CT we look at C4
- if (isCounterTerrorist() && Game.vDroppedC4 != Vector(9999, 9999, 9999)) {
- // look at dropped C4
- if (EntityIsVisible(pEdict, Game.vDroppedC4))
- vHead = Game.vDroppedC4;
- else {
- if (iGoalNode > -1)
- vHead = vBody = NodeMachine.node_vector(iGoalNode);
- else {
- // cannot find a node to the dropped C4, so where do we look at?
- // todo : find a node to look at, i.e. something dangerous
- }
- }
- } else {
- // Look at iGoalNode
- if (iGoalNode > -1)
- vHead = vBody = NodeMachine.node_vector(iGoalNode);
- else {
- // look where to look at?
- // todo : find a node to look at, i.e. something dangerous
- }
- }
- }
-
- // C4 timer is set, this means:
- // T -> Is planting bomb
- // CT-> Is defusing bomb
- if (shouldActWithC4()) {
- // make sure we override this, or else we learn that we get stuck or something
- // which is not the case.
- setTimeToMoveToNode(2);
-
- // terrorist
- if (isTerrorist()) {
- // When still having the C4
- setMoveSpeed(0.0f);
-// f_strafe_speed = 0.0;
-
- // When no C4 selected yet, select it
- if (!isHoldingWeapon(CS_WEAPON_C4)) {
- UTIL_SelectItem(pEdict, "weapon_c4");
- } else {
- UTIL_BotPressKey(this, IN_ATTACK); // plant it!
- }
-
- // When we no longer have the C4 , we stop doing this stupid shit
- if (!hasBomb() || Game.bBombPlanted) {
- rprint_trace("Act()", "I was planting the C4, and it got planted (I no longer have the C4), so find a nearby node to camp/guard the C4");
- f_c4_time = gpGlobals->time;
- setGoalNode(NodeMachine.getClosestNode(pEdict->v.origin, 200, pEdict));
- iPathFlags = PATH_CAMP;
- forgetPath();
- }
- } else {
- // counter-terrorist
- Defuse(); // old routine from RB AI V1.0 defusing, should get here and more cleaned up
- }
- }
-
- if (f_strafe_time < gpGlobals->time) {
- f_strafe_speed = 0;
- }
-
- // walk only when NOT holding duck (is same as walking, combination makes bot super slow)
- if (f_walk_time > gpGlobals->time && !(pEdict->v.button & IN_DUCK)) {
- // From "KickBot": return (float) (((int)flMaxSpeed)/2 + ((int)flMaxSpeed)/50);
- //OLD: f_move_speed = f_max_speed / 2.0; // this is not correct
-
- pEdict->v.button &= (~IN_RUN); // release IN_RUN
- rprint("Act", "Walk time > gpGlobals->time");
- setMoveSpeed((float) (((int) f_max_speed) / 2 + ((int) f_max_speed) / 50));
- }
-
- // When we are at max speed, press IN_RUN to get a running animation
- if (f_move_speed == f_max_speed) {
- UTIL_BotPressKey(this, IN_RUN);
- }
-
- if (!keyPressed(IN_MOVELEFT) || keyPressed(IN_MOVERIGHT)) {
- if (f_strafe_speed > 0.0f) {
- UTIL_BotPressKey(this, IN_MOVERIGHT);
- }
- else if (f_strafe_speed < 0.0f) {
- UTIL_BotPressKey(this, IN_MOVELEFT);
- }
- }
-
- // When we should go back, we go back
- if (f_goback_time > gpGlobals->time) {
- setMoveSpeed(-f_max_speed);
- }
-
- // When holding duck, we hold duck
- if (f_hold_duck > gpGlobals->time)
- UTIL_BotPressKey(this, IN_DUCK);
-
- // When we wait, we have no move speed
- // notice: 'wait' is not 'stuck' nor 'camping'. Wait should only be used to have a bot
- // 'do nothing' for a short period of time.
- if (f_wait_time > gpGlobals->time) {
- rprint("Act", "f_wait_time > gpGlobals->time");
- setMoveSpeed(0.0);
- }
-
- // Button usage, change vBody to a 'trigger multiple' because we have to touch these
- if (pButtonEdict) {
- if (strcmp(STRING(pButtonEdict->v.classname), "trigger_multiple") == 0) {
- if (func_distance(pEdict->v.origin, VecBModelOrigin(pButtonEdict)) < 60) {
- vBody = VecBModelOrigin(pButtonEdict);
- }
- }
- }
-
- // -------------------------------------------
- // MOVE TO : vBody
- // calculate the angle we MOVE to. (VecMoveAngles)
- // -------------------------------------------
- Vector vTarget = vBody - pEdict->v.origin;
- vecMoveAngles = UTIL_VecToAngles(vTarget);
-
- // Paulo-La-Frite - START bot aiming bug fix
- if (vecMoveAngles.x > 180)
- vecMoveAngles.x -= 360;
-
- vecMoveAngles.x = -vecMoveAngles.x;
- vecMoveAngles.z = 0;
- UTIL_FixAngles(&vecMoveAngles);
-
- // when filled in, we look to this (overrides)
- if (vEar != Vector(9999, 9999, 9999))
- vHead = vEar;
-
- // button overrides hearing
- if (pButtonEdict)
- vHead = VecBModelOrigin(pButtonEdict);
-
- // -------------------------------------------
- // FACE AT: vHead
- // calculate the angle we face at.
- //
- // -------------------------------------------
- vTarget = (vHead - pEdict->v.origin);
- pEdict->v.v_angle = UTIL_VecToAngles(vTarget);
- if (pEdict->v.v_angle.y > 180)
- pEdict->v.v_angle.y -= 360;
-
- // Paulo-La-Frite - START bot aiming bug fix
- if (pEdict->v.v_angle.x > 180)
- pEdict->v.v_angle.x -= 360;
-
- Vector v_shouldbe = pEdict->v.angles;
-
- // Vector how it should be, however, we don't allow such a fast turn!
- v_shouldbe.x = pEdict->v.v_angle.x / 3;
- v_shouldbe.y = pEdict->v.v_angle.y;
- v_shouldbe.z = 0;
-
- // set the body angles to point the gun correctly
- pEdict->v.angles.x = ReturnTurnedAngle(ipTurnSpeed, pEdict->v.angles.x, v_shouldbe.x);
- pEdict->v.angles.y = ReturnTurnedAngle(ipTurnSpeed, pEdict->v.angles.y, v_shouldbe.y);
- pEdict->v.angles.z = 0;
-
- // adjust the view angle pitch to aim correctly (MUST be after body v.angles stuff)
- pEdict->v.v_angle.x = -pEdict->v.v_angle.x;
-
- // Paulo-La-Frite - END
- pEdict->v.ideal_yaw = pEdict->v.v_angle.y;
- pEdict->v.idealpitch = pEdict->v.v_angle.x;
-
- botFixIdealYaw(pEdict);
- botFixIdealPitch(pEdict);
-}
-
-bool cBot::shouldActWithC4() const {
- return f_c4_time > gpGlobals->time;
-}
-
-// BOT: On ladder?
-bool cBot::isOnLadder() {
- return FUNC_IsOnLadder(pEdict);
-}
-
-// BOT: Check around body and avoid obstacles
-void cBot::CheckAround() {
- rprint_trace("CheckAround", "Start");
- // Do not act when on ladder
- if (isOnLadder())
- return;
-
- // The principle is to fire 2 tracelines, both forward; one left
- // and one right. When one of the 2 gets hit, we know we are 'about'
- // to get hit. Therefor we use strafing to keep distance to the coming wall
- // when left and right is both hit we have a problem as this should not happen.
-
- // Note: we use TRACEHULL instead of TRACELINE, because TRACEHULL detects
- // the famous 'undetectable' func_walls.
- TraceResult tr;
- Vector v_source, v_left, v_right, v_forward, v_forwardleft, v_forwardright;
-
-// v_source = pEdict->v.origin + Vector(0, 0, -CROUCHED_HEIGHT + (MAX_JUMPHEIGHT + 1));
- v_source = pEdict->v.origin + Vector(0, 0, ORIGIN_HEIGHT);
-
- // Go forward first
- float distance = 90;
- v_forward = v_source + gpGlobals->v_forward * distance;
-
- // now really go left/right
- v_right = v_source + gpGlobals->v_right * distance;
- v_left = v_source + gpGlobals->v_right * -distance;
-
- // now really go left/right
- v_forwardright = v_right + gpGlobals->v_forward * distance;
- v_forwardleft = v_left + gpGlobals->v_forward * -distance;
-
- // TRACELINE: forward
- UTIL_TraceHull(v_source, v_forward, dont_ignore_monsters, point_hull, pEdict->v.pContainingEntity, &tr);
- bool bHitForward = tr.flFraction < 1.0;
-
- // TRACELINE: Left
- UTIL_TraceHull(v_source, v_left, dont_ignore_monsters, point_hull, pEdict->v.pContainingEntity, &tr);
- bool bHitLeft = tr.flFraction < 1.0;
-
- // TRACELINE: Right
- UTIL_TraceHull(v_source, v_right, dont_ignore_monsters, point_hull, pEdict->v.pContainingEntity, &tr);
- bool bHitRight = tr.flFraction < 1.0;
-
- // TRACELINE: Forward left
- UTIL_TraceHull(v_source, v_forwardleft, dont_ignore_monsters, point_hull, pEdict->v.pContainingEntity, &tr);
- bool bHitForwardLeft = tr.flFraction < 1.0;
-
- // TRACELINE: Forward right
- UTIL_TraceHull(v_source, v_forwardright, dont_ignore_monsters, point_hull, pEdict->v.pContainingEntity, &tr);
- bool bHitForwardRight = tr.flFraction < 1.0;
-
-
- char msg[255];
- sprintf(msg, "HIT results: forward: %d, left: %d, right: %d, forward left: %d, forward right: %d", bHitForward, bHitLeft, bHitRight, bHitForwardLeft, bHitForwardRight);
- rprint_trace("CheckAround", msg);
-
- // Set 'act' properties
-
- // we are surrounded, so move backwards
- if (bHitForward) {
- rprint_trace("CheckAround", "Something in front of me blocks, so move back.");
-// f_move_speed = -(f_max_speed);
- } else {
- rprint_trace("CheckAround", "Nothing in front of me");
- }
-
- if (!bHitForwardLeft && bHitForwardRight) {
- strafeLeft(0.5);
- rprint_trace("CheckAround", "Can strafe left (forward left)");
- } else if (bHitForwardLeft && !bHitForwardRight) {
- strafeRight(0.5);
- rprint_trace("CheckAround", "Can strafe right (forward right)");
- }
-
- if (bHitLeft && bHitRight) {
- rprint_trace("CheckAround", "Can't strafe left or right");
- } else if (!bHitLeft && bHitRight) {
- strafeLeft(0.5);
- rprint_trace("CheckAround", "Can strafe left");
- } else if (bHitLeft && !bHitRight) {
- strafeRight(0.5);
- rprint_trace("CheckAround", "Can strafe right");
- }
-
- // -------------------------------------------------------------
- // When checking around a bot also handles breakable stuff.
- // -------------------------------------------------------------
- char item_name[40];
- edict_t *pent = NULL;
- while ((pent = UTIL_FindEntityInSphere(pent, pEdict->v.origin, 60)) != NULL) {
- strcpy(item_name, STRING(pent->v.classname));
-
- // See if it matches our object name
- if (strcmp("func_breakable", item_name) == 0) {
-
- // Found a func_breakable
- Vector vBreakableOrigin = VecBModelOrigin(pent);
-
- // Shoot
- if ((pent->v.flags & FL_WORLDBRUSH) == 0) // can it be broken?
- {
-
- // Thx for CF by fixing breakable coding
- if (pent->v.solid == SOLID_BSP && pent->v.takedamage == DAMAGE_YES && pent->v.impulse == 0 &&
- pent->v.health < 150) // has it NOT been broken yet?
- {
-
- // trace to vector to be sure we dont get blocked by anything else
- if (VectorIsVisibleWithEdict(pEdict, vBreakableOrigin, "func_breakable")) {
- setHeadAiming(vBreakableOrigin);
- FireWeapon();
- }
- return;
- }
- }
- } // CAN BE BROKEN
- } // FUNC_BREAKABLE
-}
-
-// BOT: Should be taking cover?
-bool cBot::TakeCover() {
-
- // Its time based.
- if (f_cover_time < gpGlobals->time)
- return false;
-
- // And if all went fine, we can return true.
- return true;
-}
-
-/**
- * Set the node to follow next as the next one (ie, increase index)
- */
-void cBot::nextPathIndex() {
- this->pathIndex++;
-}
-
-/**
- * Set the node to follow next as the previous one (ie, decrease index). Calls forgetPath when index is getting < 0
- */
-void cBot::prevPathIndex() {
- rprint("prevPathNodeIndex");
- this->pathIndex--;
- if (this->pathIndex < 0) {
- forgetPath();
- }
-}
-
-// Returns true if bot has a path to follow
-bool cBot::isWalkingPath() {
- return this->pathIndex > -1;
-}
-
-// Returns true if bot has goal node
-bool cBot::hasGoal() {
- return this->iGoalNode > -1;
-}
-
-// Returns true if bot has goal node index (ie referring to Goals[])
-bool cBot::hasGoalIndex() {
- return this->goalIndex > -1;
-}
-
-/**
- * Returns goal data , if goal data exists
- * @return
- */
-tGoal *cBot::getGoalData() {
- if (!hasGoalIndex()) return NULL;
- tGoal *ptr = NodeMachine.getGoal(this->goalIndex);
- if (ptr == NULL) return NULL;
-
- // only goals with a node are valid
- if (ptr->iNode > -1) return ptr;
- // else not
-
- return NULL;
-}
-
-// Returns true if bot has an enemy edict
-bool cBot::hasEnemy() {
- return this->pEnemyEdict != NULL;
-}
-
-/**
- * Returns true when given edict == our enemy edict
- * @param pEdict
- * @return
- */
-bool cBot::hasEnemy(edict_t * pEdict) {
- return this->pEnemyEdict == pEdict;
-}
-
-// Returns true if bot has a path to follow
-bool cBot::shouldBeWandering() {
- if (this->fWanderTime > gpGlobals->time) {
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Wander time is %f , globals time is %f, so should still wander", this->fWanderTime, gpGlobals->time);
- rprint(msg);
- return true;
- }
- return false;
-}
-
-void cBot::setMoveSpeed(float value) {
-// char msg[255];
-// sprintf(msg, "setting to value %f / maxSpeed %f - sv_maxspeed = %f", value, this->f_max_speed, CVAR_GET_FLOAT("sv_maxspeed"));
-// rprint_trace("setMoveSpeed", msg);
- this->f_move_speed = value;
-}
-
-void cBot::setStrafeSpeed(float value, float time) {
- char msg[255];
- sprintf(msg, "%f for %f seconds.", value, time);
- rprint_trace("setStrafeSpeed", msg);
-// if (f_strafe_time > gpGlobals->time) {
-//
-// } else {
- f_strafe_speed = value;
- f_strafe_time = gpGlobals->time + time;
-// }
-}
-
-void cBot::strafeLeft(float time) {
- setStrafeSpeed(-f_max_speed, time);
-}
-
-void cBot::strafeRight(float time) {
- setStrafeSpeed(f_max_speed, time);
-}
-
-void cBot::startWandering(float time) {
- this->fWanderTime = gpGlobals->time + time;
- setMoveSpeed(f_max_speed);
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Start wandering for %f seconds", time);
- rprint("startWandering", msg);
-}
-
-void cBot::stopMoving() {
- this->setMoveSpeed(0.0);
-}
-
-void cBot::forgetGoal() {
- rprint_trace("forgetGoal");
- this->iGoalNode = -1;
- this->goalIndex = -1;
-}
-
-int cBot::getPathIndex() {
- return this->pathIndex;
-}
-
-int cBot::getPreviousPathIndex() {
- return this->pathIndex - 1;
-}
-
-void cBot::forgetPath() {
- rprint("forgetPath");
- this->pathIndex = -1;
- NodeMachine.path_clear(this->iBotIndex);
-}
-
-void cBot::forgetEnemy() {
- this->pEnemyEdict = NULL;
-}
-
-edict_t * cBot::getEnemyEdict() {
- return this->pEnemyEdict;
-}
-
-int cBot::getGoalNode() {
- return this->iGoalNode;
-}
-
-void cBot::setGoalNode(int nodeIndex, int iGoalIndex) {
- if (nodeIndex < 0) {
- rprint("setGoalNode()", "WARN: Setting a goal lower than 0, assuming this is not intentional. If you need to forget a goal, use forgetGoal()");
- }
- this->iGoalNode = nodeIndex;
- this->goalIndex = iGoalIndex;
-
- tGoal *goalPtr = getGoalData();
- char msg[255];
- memset(msg, 0, sizeof(msg));
-
- if (goalPtr != NULL) {
- sprintf(msg, "Setting iGoalNode to [%d] and goalIndex [%d] - GOAL: type [%s], checked [%d]",
- nodeIndex,
- goalIndex,
- goalPtr->name,
- goalPtr->iChecked
- );
- } else {
- sprintf(msg, "Setting iGoalNode to [%d] and goalIndex [%d] - could not retrieve goal data.", nodeIndex, goalIndex);
- }
- rprint("setGoalNode()", msg);
-}
-
-void cBot::setGoalNode(int nodeIndex) {
- this->setGoalNode(nodeIndex, -1);
-}
-
-void cBot::setGoalNode(tGoal *goal) {
- if (goal != NULL && goal->iNode > -1) {
- rprint("setGoalNode with goal pointer\n");
- this->setGoalNode(goal->iNode, goal->index);
- }
-}
-
-/**
- * Always printed when debug mode is on
- * @param Function
- * @param msg
- */
-void cBot::rprint(const char *Function, const char *msg) {
- REALBOT_PRINT(this, Function, msg);
-}
-
-/**
- * Only printed when debug mode is on and verbosity is trace
- * @param Function
- * @param msg
- */
-void cBot::rprint_trace(const char *Function, const char *msg) {
- if (Game.messageVerbosity > 1) {
- REALBOT_PRINT(this, Function, msg);
- }
-}
-
-/**
- * Only printed when debug mode is on and verbosity is normal
- * @param Function
- * @param msg
- */
-void cBot::rprint_normal(const char *Function, const char *msg) {
- if (Game.messageVerbosity > 1) {
- REALBOT_PRINT(this, Function, msg);
- }
-}
-
-void cBot::rprint(const char *msg) {
- rprint("rprint()", msg);
-}
-
-void cBot::rprint_normal(const char *msg) {
- rprint_normal("rprint()", msg);
-}
-
-void cBot::rprint_trace(const char *msg) {
- rprint_trace("rprint()", msg);
-}
-
-bool cBot::hasBomb() {
- return isOwningWeapon(CS_WEAPON_C4);
-}
-
-bool cBot::isCounterTerrorist() {
- return iTeam == 2;
-}
-
-bool cBot::isTerrorist() {
- return iTeam == 1;
-}
-
-bool cBot::hasPrimaryWeaponEquiped() {
- return iPrimaryWeapon > -1;
-}
-
-bool cBot::hasSecondaryWeaponEquiped() {
- return iSecondaryWeapon > -1;
-}
-
-bool cBot::hasSecondaryWeapon(int weaponId) {
- return isOwningWeapon(weaponId);
-}
-
-void cBot::performBuyWeapon(const char *menuItem, const char *subMenuItem) {
- // To be sure the console will only change when we MAY change.
- // The values will only be changed when console_nr is 0
- if (Game.getRoundStartedTime() + 4 < gpGlobals->time)
- return; // Not valid to buy
-
- if (this->console_nr == 0) {
- // set up first command and argument
- strcpy(this->arg1, "buy");
- strcpy(this->arg2, menuItem);
-
- if (subMenuItem != NULL) strcpy(this->arg3, subMenuItem);
-
- this->console_nr = 1; // start console command sequence
- }
-}
-
-void cBot::performBuyActions(int weaponIdToBuy) {
- if (weaponIdToBuy < 0) {
- return;
- }
- // Buy...
-
- // TODO
- // FRASHMAN 30.08.04 haven't changed the cs 1.5 buycode, maybe there are also errors
-
- // CS 1.5 only
- if (counterstrike == 0) {
- switch (weaponIdToBuy) {
- case CS_WEAPON_AK47:
- performBuyWeapon("4", "1");
- break;
- case CS_WEAPON_DEAGLE:
- performBuyWeapon("1", "3");
- break;
- case CS_WEAPON_P228:
- performBuyWeapon("1", "4");
- break;
- case CS_WEAPON_SG552:
- performBuyWeapon("4", "2");
- break;
- case CS_WEAPON_SG550:
- performBuyWeapon("4", "8");
- break;
- case CS_WEAPON_SCOUT:
- performBuyWeapon("4", "5");
- break;
- case CS_WEAPON_AWP:
- performBuyWeapon("4", "6");
- break;
- case CS_WEAPON_MP5NAVY:
- performBuyWeapon("3", "1");
- break;
- case CS_WEAPON_UMP45:
- performBuyWeapon("3", "5");
- break;
- case CS_WEAPON_ELITE:
- performBuyWeapon("1", "5");
- break; // T only
- case CS_WEAPON_MAC10:
- performBuyWeapon("3", "4");
- break; // T only
- case CS_WEAPON_AUG:
- performBuyWeapon("4", "4");
- break; // CT Only
- case CS_WEAPON_FIVESEVEN:
- performBuyWeapon("1", "6");
- break; // CT only
- case CS_WEAPON_M4A1:
- performBuyWeapon("4", "3");
- break; // CT Only
- case CS_WEAPON_TMP:
- performBuyWeapon("3", "2");
- break; // CT only
- case CS_WEAPON_HEGRENADE:
- performBuyWeapon("8", "4");
- break;
- case CS_WEAPON_XM1014:
- performBuyWeapon("2", "2");
- break;
- case CS_WEAPON_SMOKEGRENADE:
- performBuyWeapon("8", "5");
- break;
- case CS_WEAPON_USP:
- performBuyWeapon("1", "1");
- break;
- case CS_WEAPON_GLOCK18:
- performBuyWeapon("1", "2");
- break;
- case CS_WEAPON_M249:
- performBuyWeapon("5", "1");
- break;
- case CS_WEAPON_M3:
- performBuyWeapon("2", "1");
- break;
-
- case CS_WEAPON_G3SG1:
- performBuyWeapon("4", "7");
- break;
- case CS_WEAPON_FLASHBANG:
- performBuyWeapon("8", "3");
- break;
- case CS_WEAPON_P90:
- performBuyWeapon("3", "3");
- break;
-
- // Armor
- case CS_WEAPON_ARMOR_LIGHT:
- performBuyWeapon("8", "1");
- break;
- case CS_WEAPON_ARMOR_HEAVY:
- performBuyWeapon("8", "2");
- break;
-
- case CS_DEFUSEKIT:
- performBuyWeapon("8", "6");
- break;
- }
- }
-
- // CS 1.6 only
- if (counterstrike == 1) { // FRASHMAN 30/08/04: redone switch block, it was full of errors
- switch (weaponIdToBuy) {
- //Pistols
- case CS_WEAPON_GLOCK18:
- performBuyWeapon("1", "1");
- break;
- case CS_WEAPON_USP:
- performBuyWeapon("1", "2");
- break;
- case CS_WEAPON_P228:
- performBuyWeapon("1", "3");
- break;
- case CS_WEAPON_DEAGLE:
- performBuyWeapon("1", "4");
- break;
- case CS_WEAPON_ELITE:
- performBuyWeapon("1", "5");
- break;
- //ShotGUNS
- case CS_WEAPON_M3:
- performBuyWeapon("2", "1");
- break;
- case CS_WEAPON_XM1014:
- performBuyWeapon("2", "2");
- break;
- //SMG
- case CS_WEAPON_MAC10:
- performBuyWeapon("3", "1");
- break;
- case CS_WEAPON_TMP:
- performBuyWeapon("3", "1");
- break;
- case CS_WEAPON_MP5NAVY:
- performBuyWeapon("3", "2");
- break;
- case CS_WEAPON_UMP45:
- performBuyWeapon("3", "3");
- break;
- case CS_WEAPON_P90:
- performBuyWeapon("3", "4");
- break;
- //rifles
- case CS_WEAPON_GALIL:
- performBuyWeapon("4", "1");
- break;
- case CS_WEAPON_FAMAS:
- performBuyWeapon("4", "1");
- break;
- case CS_WEAPON_AK47:
- performBuyWeapon("4", "2");
- break;
- case CS_WEAPON_M4A1:
- performBuyWeapon("4", "3");
- break;
- case CS_WEAPON_SG552:
- performBuyWeapon("4", "4");
- break;
- case CS_WEAPON_AUG:
- performBuyWeapon("4", "4");
- break;
- case CS_WEAPON_SG550:
- performBuyWeapon("4", "5");
- break;
- case CS_WEAPON_G3SG1:
- performBuyWeapon("4", "6");
- break;
- //machinegun
- case CS_WEAPON_M249:
- performBuyWeapon("5", "1");
- break;
- // equipment
- case CS_WEAPON_ARMOR_LIGHT:
- performBuyWeapon("8", "1");
- break;
- case CS_WEAPON_ARMOR_HEAVY:
- performBuyWeapon("8", "2");
- break;
- case CS_WEAPON_FLASHBANG:
- performBuyWeapon("8", "3");
- break;
- case CS_WEAPON_HEGRENADE:
- performBuyWeapon("8", "4");
- break;
- case CS_WEAPON_SMOKEGRENADE:
- performBuyWeapon("8", "5");
- break;
- case CS_WEAPON_SHIELD:
- performBuyWeapon("8", "8");
- break;
-
- case CS_DEFUSEKIT:
- performBuyWeapon("8", "6");
- break;
- }
-
- // This differs per team
- // FRASHMAN 30/08/04: all into one ifthen block
- if (iTeam == 2) // counter
- {
- switch (weaponIdToBuy) {
- case CS_WEAPON_SCOUT:
- performBuyWeapon("4", "2");
- break;
- case CS_WEAPON_AWP:
- performBuyWeapon("4", "6");
- break;
- //whats about nightvision? BuyWeapon (pBot, "8", "7")
- }
- } else // terror
- {
- switch (weaponIdToBuy) {
- case CS_WEAPON_SCOUT:
- performBuyWeapon("4", "3");
- break;
- case CS_WEAPON_AWP:
- performBuyWeapon("4", "5");
- break;
- //whats about nightvision? BuyWeapon (pBot, "8", "6")
- }
- }
- } // end of cs 1.6 part
-} // We actually gonna buy this weapon
-
-// BOT: Memory()
-// In this function the bot will receive data; this can be any kind of data.
-// For hearing, the bot will check for sounds it should pay attention to and
-// store this into its 'hearing vector'. The hearing vector will be used only
-// when walking and not when fighting an enemy. Do note that this hearing vector
-// is only filled when it is important enough, so all the decisions are made here.
-void cBot::Memory() {
-
- // Skip method when it is too soon.
- if (fMemoryTime > gpGlobals->time) {
- return;
- }
-
- // Hear players: (loop through all players, determine if they are running and if
- // we can hear them (estimated distance)).
- if (pEnemyEdict == NULL) {
- Vector vHear = Vector(9999, 9999, 9999);
- edict_t *pHearPlayer = NULL;
-
- //f_walk_time = gpGlobals->time + 1;
-
- for (int i = 1; i <= gpGlobals->maxClients; i++) {
- edict_t *pPlayer = INDEXENT(i);
-
- // skip invalid players and skip self (i.e. this bot)
- if ((pPlayer) && (!pPlayer->free) && (pPlayer != pEdict)) {
- // skip this player if not alive (i.e. dead or dying)
- if (!IsAlive(pPlayer))
- continue;
-
- // check if we can 'see it on radar' (skip teammates)
- if (UTIL_GetTeam(pPlayer) == UTIL_GetTeam(pEdict))
- continue;
-
- // check if its running
- if (FUNC_PlayerRuns(FUNC_PlayerSpeed(pPlayer))) {
- // check distance
- float fDistance =
- (pPlayer->v.origin - pEdict->v.origin).Length();
-
- // estimated distance we can hear somebody
- if (fDistance < BOT_HEARDISTANCE) {
- // check if this 'hearing' vector is closer then our previous one
- if (vHear != Vector(9999, 9999, 9999)) {
- if (func_distance
- (pEdict->v.origin,
- pPlayer->v.origin) <
- func_distance(pEdict->v.origin, vHear)) {
- // this one is closer, thus more important
- vHear = pPlayer->v.origin;
- pHearPlayer = pPlayer;
- }
- } else {
- vHear = pPlayer->v.origin;
- pHearPlayer = pPlayer;
- }
- }
- }
-
-
- if ((pPlayer->v.button & IN_ATTACK)
- && (FUNC_EdictHoldsWeapon(pEdict) != CS_WEAPON_HEGRENADE
- && FUNC_EdictHoldsWeapon(pEdict) != CS_WEAPON_FLASHBANG
- && FUNC_EdictHoldsWeapon(pEdict) !=
- CS_WEAPON_SMOKEGRENADE)) {
- // check distance
- float fDistance =
- (pPlayer->v.origin - pEdict->v.origin).Length();
-
- // estimated distance we can hear somebody
- if (fDistance < BOT_HEARFIREDISTANCE) {
- // check if this 'hearing' vector is closer then our previous one
- if (vHear != Vector(9999, 9999, 9999)) {
- if (func_distance
- (pEdict->v.origin,
- pPlayer->v.origin) <
- func_distance(pEdict->v.origin, vHear)) {
- // this one is closer, thus more important
- vHear = pPlayer->v.origin;
- pHearPlayer = pPlayer;
- }
- } else {
- vHear = pPlayer->v.origin;
- pHearPlayer = pPlayer;
- }
- }
- }
- // zooming of a sniper rifle
- if (pPlayer->v.button & IN_ATTACK2) {
- // check distance
- float fDistance =
- (pPlayer->v.origin - pEdict->v.origin).Length();
-
- // estimated distance we can hear somebody
- if (fDistance < BOT_HEARDISTANCE) {
- // check if this 'hearing' vector is closer then our previous one
- if (vHear != Vector(9999, 9999, 9999)) {
- if (func_distance
- (pEdict->v.origin,
- pPlayer->v.origin) <
- func_distance(pEdict->v.origin, vHear)) {
- // this one is closer, thus more important
- vHear = pPlayer->v.origin;
- pHearPlayer = pPlayer;
- }
- } else {
- vHear = pPlayer->v.origin;
- pHearPlayer = pPlayer;
- }
- }
- }
-
- }
- }
-
- // Fill in hearing vectory if any:
- if (pHearPlayer != NULL) {
- if (RANDOM_LONG(0, 100) < (ipFearRate + 10)) {
-
- // determine fuzzyness by distance:
- int iFuzz =
- (int) (func_distance(pEdict->v.origin, vHear) /
- BOT_HEARDISTANCE) * 250;
-
- // skill depended
- iFuzz /= (bot_skill + 1);
-
- // create 'estimated hear vector'
- vHear =
- vHear + Vector(RANDOM_LONG(-iFuzz, iFuzz),
- RANDOM_LONG(-iFuzz, iFuzz),
- RANDOM_LONG(-iFuzz, iFuzz));
-
- TraceResult tr;
-
- UTIL_TraceHull(pEdict->v.origin, vHear, dont_ignore_monsters,
- point_hull, pEdict, &tr);
-
- int iNodeHearPlayer =
- NodeMachine.getClosestNode(vHear, NODE_ZONE * 2, pHearPlayer);
-
- // if nothing hit:
- if (tr.flFraction >= 1.0) {
- // we can look at this spot
- vEar = vHear;
- }
- // we go to the destination
-
- float fTime = 5 + (ipFearRate / 7);
-
- if (RANDOM_LONG(0, 100) < ipFearRate
- && f_walk_time + 5 < gpGlobals->time) // last 5 seconds did not walk
- f_walk_time = gpGlobals->time + fTime;
-
- if (RANDOM_LONG(0, 100) < ipCampRate
- && f_camp_time + 30 < gpGlobals->time // last 30 seconds did not camp
- ) {
- f_camp_time = gpGlobals->time + fTime;
- }
-
- } else {
- fMemoryTime = gpGlobals->time + 5;
- }
-
- /*
-
-
- int iNodeHearPlayer = NodeMachine.getCloseNode (vHear, NODE_ZONE*2, pHearPlayer);
- int iNodeFrom = NodeMachine.getCloseNode (pEdict->v.origin, NODE_ZONE*2, pEdict);
- int iHearToNode = NodeMachine.node_look_at_hear(iNodeHearPlayer, iNodeFrom, pEdict);
-
- // look at hearto node
- if (iHearToNode > -1)
- {
- vHead = NodeMachine.node_vector(iHearToNode);
- SERVER_PRINT("found smart look at node\n");
- }
-
- // only check for new goal when the current goal is way of distance and such
- if (ipCampRate > 30 && f_camp_time + 5 < gpGlobals->time)
- f_camp_time = gpGlobals->time + 2.5;
- */
-
- if (f_update_weapon_time + 2 < gpGlobals->time) {
- PickBestWeapon();
- }
- } else {
- vEar = Vector(9999, 9999, 9999);
-//
-// // check for any 'beeps' of the bomb!
-// if (isCounterTerrorist() && Game.bBombPlanted) {
-// // find the bomb vector
-// edict_t *pent = NULL;
-// Vector vC4 = Vector(9999, 9999, 9999);
-// while ((pent = UTIL_FindEntityByClassname(pent, "grenade")) != NULL) {
-// if (UTIL_GetGrenadeType(pent) == 4) // It is a C4
-// {
-// vC4 = pent->v.origin; // store origin
-// break; // done our part now
-// }
-// } // --- find the c4
-//
-// if (vC4 != Vector(9999, 9999, 9999)) {
-//
-// if (func_distance(vC4, NodeMachine.node_vector(iGoalNode)) > 100 &&
-// func_distance(pEdict->v.origin, vC4) < 1024) {
-// // set new goal node
-// setGoalNode(NodeMachine.getCloseNode(vC4, NODE_ZONE, NULL));
-// forgetPath();
-// }
-// }
-// }
- }
-
- } else {
- vEar = Vector(9999, 9999, 9999);
- }
-}
-
-
-// BOT: Do i carry weapon # now?
-bool cBot::CarryWeapon(int iType) {
- if (current_weapon.iId == iType)
- return true;
- return false;
-}
-
-// BOT: Do i carry weapon TYPE # now?
-int cBot::CarryWeaponType() {
- int kind = PRIMARY;
- int weapon_id = current_weapon.iId;
-
- // Check 1. Is it a knife?
- if (weapon_id == CS_WEAPON_KNIFE)
- kind = KNIFE;
-
- // Check 2, is it a 'tool'?
- if (weapon_id == CS_WEAPON_FLASHBANG || weapon_id == CS_WEAPON_HEGRENADE
- || weapon_id == CS_WEAPON_SMOKEGRENADE)
- kind = GRENADE;
-
- // Check 3, is it a secondary gun?
- if (weapon_id == CS_WEAPON_P228 || weapon_id == CS_WEAPON_ELITE
- || weapon_id == CS_WEAPON_UMP45 || weapon_id == CS_WEAPON_USP
- || weapon_id == CS_WEAPON_GLOCK18 || weapon_id == CS_WEAPON_DEAGLE
- || weapon_id == CS_WEAPON_FIVESEVEN)
- kind = SECONDARY;
-
- // Check 4, is it a sniper gun?
- if (weapon_id == CS_WEAPON_SCOUT || weapon_id == CS_WEAPON_SG550
- || weapon_id == CS_WEAPON_AWP || weapon_id == CS_WEAPON_G3SG1)
- kind = SNIPER;
-
- if (hasShield()) {
- kind = SHIELD;
- }
- //if (weapon_id < 1)
- // kind = NONE;
- return kind;
-}
-
-// BOT: Think about objectives
-//
-// This function only takes action when the bot is close a goal. The function
-// NodeMachine.path_think() handles WHERE the bot goes. Not WHAT to do at a goal.
-void cBot::ThinkAboutGoals() {
- //REALBOT_PRINT(this, "thinkAboutGoals()", "start");
- // Depending on bot team we handle goals differently:
- // TERRORISTS
- if (isTerrorist()) {
- // Plant the bomb when the HUD says we can -- BERKED
- if (bHUD_C4_plantable)
- f_c4_time = gpGlobals->time + 1; // plant bomb
-
- // A dropped C4 is not a 'goal' (ie. it won't let you win the game
- // when you pick up the bomb. Therefor the 'pickup the dropped bomb
- // code is in cNodeMachine::path_walk().
- } else if (isCounterTerrorist()) {
- // COUNTER-TERRORISTS
- if (vip) {
- // VIP
- } else {
- if (Game.bBombPlanted) {
- if (isCounterTerrorist()) {
- // defuse (or set timers for it)
- Defuse();
- }
- } else {
- if (Game.bHostageRescueMap) {
- TryToGetHostageTargetToFollowMe(this);
- checkIfHostagesAreRescued();
- checkOfHostagesStillFollowMe();
- }
- }
- }
- }
- // in Act() we find the 'acting' code when timers above are set.
-}
-
-void cBot::rememberWhichHostageToRescue(edict_t *pHostage) {
- this->pBotHostage = pHostage;
-}
-
-edict_t * cBot::getHostageToRescue() {
- return pBotHostage;
-}
-
-edict_t * cBot::findHostageToRescue() {
- edict_t *pent = NULL;
-
- // Search for all hostages in the game
- while ((pent = UTIL_FindEntityByClassname(pent, "hostage_entity")) != NULL) {
- if (!isHostageRescueable(this, pent)) continue;
- if (!canSeeEntity(pent)) continue;
- // skip too far hostages, leave it up to the goal picking to get closer
- if (getDistanceTo(pent->v.origin) > (NODE_ZONE * 2.5)) continue;
-
- char msg[255];
- sprintf(msg, "Found hostage to rescue at %f,%f,%f", pent->v.origin.x, pent->v.origin.y, pent->v.origin.z);
- this->rprint_trace("findHostageToRescue()", msg);
- return pent;
- }
-
- return NULL;
-}
-
-bool cBot::isDefusing() {
- return f_defuse > gpGlobals->time;
-}
-
-bool cBot::hasTimeToMoveToNode() {
- return fMoveToNodeTime > -1 && getMoveToNodeTimeRemaining() > 0;
-}
-/**
-This function will set the iCloseNode variable, which is the node most closest to
-the bot. Returns the closest node it found.
-**/
-int cBot::determineCurrentNode() {
- iCloseNode = determineCurrentNode(NODE_ZONE);
- return iCloseNode;
-}
-
-/**
-This function will set the iCloseNode variable, which is the node most closest to
-the bot. Returns the closest node it found.
-**/
-int cBot::determineCurrentNodeWithTwoAttempts() {
- iCloseNode = determineCurrentNode();
- if (iCloseNode < 0) {
- iCloseNode = determineCurrentNode(NODE_ZONE * 2);
- }
- return iCloseNode;
-}
-
-/**
-Find node close to bot, given range. Does not cache result.
-**/
-int cBot::determineCurrentNode(float range) {
- return NodeMachine.getClosestNode(pEdict->v.origin, range, pEdict);
-}
-
-/**
- * This returns the current node (iCloseNode) set. Instead of using determineCurrentNode, which is expensive,
- * call this to return the cached value. It will however call determineCurrentNode when node is < 0, usually it means
- * the state has been set.
- * @return
- */
-int cBot::getCurrentNode() {
- if (iCloseNode < 0) {
- determineCurrentNode();
- }
- return iCloseNode;
-}
-
-/**
- * Aka, the node we are heading for.
- */
-int cBot::getCurrentPathNodeToHeadFor() {
- return NodeMachine.getNodeIndexFromBotForPath(iBotIndex, pathIndex);
-}
-
-/**
- * Aka, the node we were coming from. In case the index is < 0 (ie, there is no previous node yet), this will
- * return -1;
- */
-int cBot::getPreviousPathNodeToHeadFor() {
- return NodeMachine.getNodeIndexFromBotForPath(iBotIndex, getPreviousPathIndex());
-}
-
-bool cBot::isHeadingForGoalNode() {
- return getCurrentPathNodeToHeadFor() == getGoalNode();
-}
-
-/**
- * Aka, the next node after we have arrived at the current path node.
- */
-int cBot::getNextPathNode() {
- return NodeMachine.getNodeIndexFromBotForPath(iBotIndex, pathIndex + 1);
-}
-
-// Is this bot dead?
-bool cBot::isDead() {
- return (pEdict->v.health < 1) || (pEdict->v.deadflag != DEAD_NO);
-}
-
-// BOT: Think
-void cBot::Think() {
- if (mod_id != CSTRIKE_DLL) return; // do not support non-counter-strike mods
-
- // BOT: If a bot did not join a team yet, then do it
- if (!hasJoinedTeam) {
- rprint("Need to join team, doing that now");
- JoinTeam();
- return;
- }
-
- // Set closest node
- determineCurrentNode();
-
- // BOT: If a bot is dead, re-initialize
- if (isDead()) {
- if (!bInitialize) return; // do nothing when no need to initialize
- rprint("Dead, need to re-initialize");
-
- // AUTOSKILL
- cBot *botPointerOfKiller = UTIL_GetBotPointer(killer_edict);
-
- // not killed by a fellow bot, presumably a human player
- if (botPointerOfKiller == NULL) {
- if (autoskill) {
- bot_skill--;
- if (bot_skill < 0)
- bot_skill = 0;
- }
-
- if (Game.iKillsBroadcasting != BROADCAST_KILLS_NONE
- && killer_edict != NULL) {
- // This is a human, we will tell this human he has been killed
- // by a bot.
- int r = RANDOM_LONG(150, 255);
- int g = RANDOM_LONG(30, 155);
- int b = RANDOM_LONG(30, 155);
- char msg[128];
- if (Game.iDeathsBroadcasting == BROADCAST_DEATHS_FULL)
- sprintf(msg,
- "You have killed a RealBot!\n\nName:%s\nSkill:%d\n",
- name, bot_skill);
- else
- sprintf(msg, "You have killed a RealBot named %s!",
- name);
-
- HUD_DrawString(r, g, b, msg, killer_edict);
- }
- }
-
- if (iCloseNode > -1 && !end_round) {
- iDiedNode = iCloseNode;
- NodeMachine.danger(iCloseNode, UTIL_GetTeam(pEdict));
- }
-
- if (console_nr == 0) {
- rprint("NewRound - because console_nr ?!");
- NewRound();
- bInitialize = false;
- }
-
- BotConsole(this);
-
- // dead messages
- if (console_nr == 0) {
- rprint("console_nr == 0"); //whatever this means
- // do some chatting
- if (RANDOM_LONG(0, 200) < ipChatRate) {
- if (fChatTime + 0.5 < gpGlobals->time)
- if (chChatSentence[0] == '\0') // we did not want to say anything
- {
- // we should say something now?
- int iMax = -1;
-
- for (int tc = 0; tc < 50; tc++) {
- if (ChatEngine.ReplyBlock[99].sentence[tc][0] != '\0') iMax++;
- }
-
- int the_c = RANDOM_LONG(0, iMax);
-
- if (the_c > -1 && iMax > -1) {
- char chSentence[80];
- memset(chSentence, 0, sizeof(chSentence));
- sprintf(chSentence, "%s ",
- ChatEngine.ReplyBlock[99].sentence[the_c]);
- //strcpy(chSentence, ChatEngine.ReplyBlock[99].sentence[the_c]);
- PrepareChat(chSentence);
- }
- }
- } else {
- // we missed the chatrate chance
- if (fChatTime < gpGlobals->time) // time
- if (chChatSentence[0] == '\0') // we did not want to say anything
- if (RANDOM_LONG(0, 100) < ipChatRate) // rate
- fChatTime = gpGlobals->time +
- RANDOM_FLOAT(0.0, ((Game.iProducedSentences + 1) / 2)); // wait
-
- }
-
- return;
- }
- } // isDead();
-
- // set this for the next time the bot dies so it will initialize stuff
- if (!bInitialize) {
- bInitialize = true;
- }
-
- if (end_round) {
- rprint("End round");
- MDLL_ClientKill(pEdict);
- pEdict->v.frags += 1;
- return;
- }
-
- // BOT: Played enough rounds
- if (played_rounds > play_rounds && internet_play) {
- rprint("Played enough rounds");
- bIsUsed = FALSE; // no longer used
- char cmd[80];
- sprintf(cmd, "kick \"%s\"\n", name);
- SERVER_COMMAND(cmd); // kick the bot using (kick "name")
- return;
- }
-
- // Move speed... moved_distance.
- if (distanceMovedTimer <= gpGlobals->time) {
- // see how far bot has moved since the previous position...
- Vector v_diff = prevOrigin - pEdict->v.origin;
- // make distanceMoved an average of this moment and the previous one.
- float movedTwoTimes = distanceMoved + v_diff.Length();
-
- // prevent division by zero
- if (movedTwoTimes > 0.0f) {
- distanceMoved = movedTwoTimes / 2;
- } else {
- distanceMoved = 0;
- }
-
- // save current position as previous
- prevOrigin = pEdict->v.origin;
- distanceMovedTimer = gpGlobals->time + 0.1;
- }
-
- // NEW ROUND
- if (Game.NewRound()) {
- rprint_trace("Think", "Game.NewRound");
- }
-
- // --------------------------------
- // MEMORY STEP
- // --------------------------------
- Memory();
-
- // --------------------------------
- // IMPORTANT THINKING GOING ON HERE
- // --------------------------------
- int healthChange = prev_health - bot_health;
-
- // handle damage taken
- if (prev_health > bot_health
- && healthChange > RANDOM_LONG(CSTRIKE_MIN_DAMAGE, CSTRIKE_MAX_DAMAGE)
- && hasEnemy()) {
-
- // need backup!
- if (FUNC_DoRadio(this)) {
- UTIL_BotRadioMessage(this, 3, "3", "");
- }
-
- BOT_DecideTakeCover(this);
- }
-
- prev_health = bot_health;
-
- // Do your console stuff
- BotConsole(this);
-
- // BOT: Blinded
- if (isBlindedByFlashbang()) {
- // Dude we are messed up.
-
- // 01/07/04 - Stefan - Pointed out on the forums by Josh Borke... (do not shoot when dontshoot is on)
- // shoot randomly
- if (!Game.bDoNotShoot) {
- if ((RANDOM_LONG(0, 100) < ipFearRate) && RANDOM_LONG(0, 100)) {
- UTIL_BotPressKey(this, IN_ATTACK);
- }
- }
-
- rprint_trace("Think()", "Blinded");
- return;
- }
-
-
- // NEW: When round time is over and still busy playing, kill bots
- float roundTimeInSeconds = CVAR_GET_FLOAT("mp_roundtime") * 60;
- float freezeTimeCVAR = CVAR_GET_FLOAT("mp_freezetime");
- if (Game.getRoundStartedTime() + 10.0 + roundTimeInSeconds + freezeTimeCVAR < gpGlobals->time) {
- end_round = true;
- // round is ended
- }
-
- // FREEZETIME:
- if (Game.getRoundStartedTime() > gpGlobals->time && freezeTime < gpGlobals->time) {
- freezeTime = gpGlobals->time + RANDOM_FLOAT(0.1, 2.0);
- }
-
- // 1 SECOND START OF ROUND
- if (Game.getRoundStartedTime() + 1 > gpGlobals->time &&
- Game.getRoundStartedTime() < gpGlobals->time) {
- // TODO: Issue radio command?
- this->rprint_trace("cBot::Think()", "First second of round");
- }
-
- // SITUATION: In freezetime
- if (isFreezeTime()) {
- stopMoving();
- lastSeenEnemyVector = Vector(0, 0, 0);
- setTimeToMoveToNode(2);
- vHead = vBody = pEdict->v.origin;
-
- // find any spawnpoint to look at:
- edict_t *pent = NULL;
-
- if (isCounterTerrorist()) {
- while ((pent = UTIL_FindEntityByClassname(pent, "info_player_start")) != NULL) {
- if (func_distance(pent->v.origin, pEdict->v.origin) < 200 &&
- func_distance(pent->v.origin, pEdict->v.origin) > 50) {
- break;
- }
- }
- } else {
- while ((pent = UTIL_FindEntityByClassname(pent, "info_player_deathmatch")) != NULL) {
- if (func_distance(pent->v.origin, pEdict->v.origin) < 200 &&
- func_distance(pent->v.origin, pEdict->v.origin) > 50) {
- break;
- }
- }
- }
-
- // when pent is filled, look at it
- if (pent != NULL) {
- vBody = vHead = pent->v.origin;
- }
-
- rprint_trace("Think()", "isFreezeTime");
- return;
- }
-
- // **---**---**---**---**---**---**
- // MAIN STATE: We have no enemy...
- // **---**---**---**---**---**---**
- if (!hasEnemy()) {
-
- if (!Game.bDoNotShoot) {
- InteractWithPlayers();
- }
-
- bool bMayFromGame = true;
-
- if (Game.fWalkWithKnife > 0)
- if (Game.getRoundStartedTime() + Game.fWalkWithKnife < gpGlobals->time)
- bMayFromGame = false;
-
- if (Game.fWalkWithKnife == 0)
- bMayFromGame = false;
-
- if (hasShield()) {
- if (!hasShieldDrawn() && f_allow_keypress < gpGlobals->time) {
- UTIL_BotPressKey(this, IN_ATTACK2); // draw shield
- f_allow_keypress = gpGlobals->time + 0.7;
- }
- }
-
- if (CarryWeapon(CS_WEAPON_KNIFE) == false
- && f_camp_time < gpGlobals->time
- && freezeTime < gpGlobals->time
- && f_c4_time < gpGlobals->time
- && f_update_weapon_time < gpGlobals->time && bWalkKnife
- && bMayFromGame) {
- UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(-1)); // -1 is knife
- f_update_weapon_time = gpGlobals->time + 0.7;
- }
-
- // When holding a grenade (and not switching to another weapon)
- if (CarryWeaponType() == GRENADE
- && f_update_weapon_time < gpGlobals->time) {
- if (iPrimaryWeapon > -1)
- UTIL_SelectItem(pEdict,
- UTIL_GiveWeaponName(iPrimaryWeapon));
-
- else // pick secondary
- UTIL_SelectItem(pEdict,
- UTIL_GiveWeaponName(iSecondaryWeapon));
- f_update_weapon_time = gpGlobals->time + 0.7;
- }
-
- // Think about objectives
- ThinkAboutGoals();
- } else {
- // **---**---**---**---**---**---**
- // MAIN STATE: We have an enemy!
- // **---**---**---**---**---**---**
-
- // Keep interacting with players:
- InteractWithPlayers();
-
- // And combat enemies
- Combat();
- }
-
- // WALK()
- NodeMachine.path_think(this, distanceMoved);
-
- // SITUATION: Passed Freezetime
-
-} // THINK()
-
-bool cBot::isFreezeTime() const {
- return freezeTime > gpGlobals->time;
-}
-
-/**
-Return true if one of the pointers is not NULL
-**/
-bool cBot::isEscortingHostages() {
- bool result = getAmountOfHostagesBeingRescued() > 0;
- if (result) {
- rprint("I am escorting hostages!");
- }
- return result;
-}
-
-void cBot::checkOfHostagesStillFollowMe() {
- if (fCheckHostageStatusTimer > gpGlobals->time) return;
- fCheckHostageStatusTimer = gpGlobals->time + 5;
-
-//// this->rprint("checkOfHostagesStillFollowMe - START");
-// if (hostage1) {
-// if (!isHostageRescued(this, hostage1) && FUNC_EdictIsAlive(hostage1) && !canSeeEntity(hostage1) && getDistanceTo(hostage1->v.origin) > NODE_ZONE*2.5) {
-// rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage1");
-// forgetHostage(hostage1);
-// }
-// }
-// if (hostage2) {
-// if (!isHostageRescued(this, hostage2) && FUNC_EdictIsAlive(hostage2) && !canSeeEntity(hostage2) && getDistanceTo(hostage2->v.origin) > NODE_ZONE*2.5) {
-// rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage2");
-// forgetHostage(hostage2);
-// }
-// }
-// if (hostage3) {
-// if (!isHostageRescued(this, hostage3) && FUNC_EdictIsAlive(hostage3) && !canSeeEntity(hostage3) && getDistanceTo(hostage3->v.origin) > NODE_ZONE*2.5) {
-// rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage3");
-// forgetHostage(hostage3);
-// }
-// }
-//
-// if (hostage4) {
-// if (!isHostageRescued(this, hostage4) && FUNC_EdictIsAlive(hostage4) && !canSeeEntity(hostage4) && getDistanceTo(hostage4->v.origin) > NODE_ZONE*2.5) {
-// rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage4");
-// forgetHostage(hostage4);
-// }
-// }
-// rprint("checkOfHostagesStillFollowMe - END");
-}
-
-void cBot::clearHostages() {
- rprint_trace("clearHostages");
- hostage1 = NULL;
- hostage2 = NULL;
- hostage3 = NULL;
- hostage4 = NULL;
- pBotHostage = NULL;
-}
-
-// BOT: CheckGear, part of UpdateStatus()
-void cBot::CheckGear() {
-
- // PRIMARY
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_mp5navy"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_mp5navy");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_ak47"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_ak47");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_m3"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_m3");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_aug"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_aug");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_sg552"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_sg552");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_m249"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_m249");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_xm1014"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_xm1014");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_p90"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_p90");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_tmp"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_tmp");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_m4a1"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_m4a1");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_awp"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_awp");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_sg550"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_sg550");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_scout"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_scout");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_mac10"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_mac10");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_g3sg1"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_g3sg1");
-
- // Counter-Strike 1.6 weapon FAMAS/GALIL
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_famas"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_famas");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_galil"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_galil");
-
- // SECONDARY
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_ump45"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_ump45");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_elite"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_elite");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_fiveseven"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_fiveseven");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_p228"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_p228");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_deagle"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_deagle");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_usp"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_usp");
- if (isOwningWeapon(UTIL_GiveWeaponId("weapon_glock18"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_glock18");
-
- // Handle shields as primary weapon
- if (hasShield()) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_shield");
-}
-
-// BOT: Update personal status
-void cBot::UpdateStatus() {
- // name filled in yet?
- if (name[0] == 0)
- strcpy(name, STRING(pEdict->v.netname));
-
- // Set thirdpartybot flag
- pEdict->v.flags |= FL_THIRDPARTYBOT;
-
- // Reset stuff
- pEdict->v.button = 0;
- setMoveSpeed(f_max_speed); // by default run
-
- // When its not time to strafe, don't.
- if (f_strafe_time < gpGlobals->time) {
- if (f_strafe_speed != 0.0f) {
- rprint_trace("UpdateStatus", "Strafe speed set to 0!");
- f_strafe_speed = 0.0f;
- }
- }
-
- // Update team state when started
- if (hasJoinedTeam) {
- iTeam = UTIL_GetTeam(pEdict) + 1; // 1 - TERRORIST, 2 - COUNTER-TERRORIST
- }
-
- // Check if we became VIP
- vip = UTIL_IsVip(pEdict);
-
- // Check gear
- CheckGear();
-
- // Set max speed and such when CS 1.6
- if (counterstrike == 1) {
- f_max_speed = pEdict->v.maxspeed;
-// char msg[255];
-// sprintf(msg, "f_max_speed set to %f", f_max_speed);
-// rprint_trace("UpdateStatus", msg);
- bot_health = (int) pEdict->v.health;
- bot_armor = (int) pEdict->v.armorvalue;
- }
-}
-
-// ---------------------------------- BOT CLASS FUNCTIONS
-// ---------------------------------- BOT CLASS FUNCTIONS
-// ---------------------------------- BOT CLASS FUNCTIONS
-
-////////////////////////////////////////////////////////////////////////////////
-/// Radio Action - Response
-////////////////////////////////////////////////////////////////////////////////
-bool BotRadioAction() {
- char name[64];
- bool unstood = false;
- edict_t *plr = NULL;
- int team = -1;
- int i;
- int radios = 0; // Hold amount of replies here, so we don't flood :)
- strcpy(name, radio_messenger);
-
- // First find the team messager name
- for (i = 1; i <= gpGlobals->maxClients; i++) {
- edict_t *pPlayer = INDEXENT(i); // Get pEdict
- char netname[64];
- if (pPlayer) // If player exists
- {
- strcpy(netname, STRING(pPlayer->v.netname)); // Copy netname
- if (strcmp(netname, name) == 0) // If
- {
- plr = pPlayer;
- team = UTIL_GetTeam(pPlayer);
- }
- }
- }
-
- // Check players and check if radio message applies to them
- for (i = 1; i <= gpGlobals->maxClients; i++) {
- edict_t *pPlayer = INDEXENT(i);
- char netname[64];
- if (pPlayer) {
-
- strcpy(netname, STRING(pPlayer->v.netname));
-
- if ((strcmp(netname, name) != 0) && // When not the same name
- (team == UTIL_GetTeam(pPlayer)) && // .. the same team...
- (pPlayer->v.deadflag == DEAD_NO) && // .. not dead ..
- ((UTIL_GetBotPointer(pPlayer) != NULL))) // and a RealBot
- {
- // here are all bots
- cBot *BotPointer = UTIL_GetBotPointer(pPlayer);
-
- if (BotPointer == NULL)
- continue; // somehow this fucked up, bail out
-
- bool want_to_answer = false; // want to answer radio call
- bool report_back = false; // for reporting in
- float distance = func_distance(plr->v.origin,
- BotPointer->pEdict->v.origin); // distance between the 2
-
- // Same team, randomly, do we even listen to the radio?
- // the more further away, the more chance it will not listen
- bool bWantToListen = false;
-
- // Reply on distance check
- if (RANDOM_LONG(0, 8192) > distance)
- bWantToListen = true;
-
- // Hearrate (personality setting)
- if (RANDOM_LONG(0, 100) < BotPointer->ipHearRate &&
- bWantToListen)
- want_to_answer = true;
-
- bool can_do_negative = true; // On some radio commands we can't say negative, thats stupid
-
- // If we want to listen to the radio... then handle it!
- if (bWantToListen) {
-
- // Report in team!
- if (strstr(message, "#Report_in_team") != NULL) {
- // gives human knowledge who is on his team
- }
-
- // Regroup team!
- if (strstr(message, "#Regroup_team") != NULL) {
- // regroup now!
- unstood = true;
-
- // get to the leader position
- BotPointer->rprint("Setting goal from regroup team");
- BotPointer->setGoalNode(NodeMachine.getClosestNode(plr->v.origin, NODE_ZONE * 2, plr));
- BotPointer->forgetPath();
- }
-
- // Hold this position
- if (strstr(message, "#Hold_this_position") != NULL ||
- strstr(message, "#Get_in_position_and_wait") != NULL) {
- // do nothing
- }
- // Follow me!!
- if (strstr(message, "#Follow_me") != NULL) {}
-
- // You take the point!
- // 23/06/04 - Stefan - Here the leader should break up his position?
- // ie, the leader will be assigned to the bot this human/bot is facing?
- if (strstr(message, "#You_take_the_point") != NULL) {
- can_do_negative = false;
- }
- // Enemy Sotted!
- if (strstr(message, "#Enemy_spotted") != NULL) {
- can_do_negative = false;
-
- // Find player who issues this message and go to it
- int iBackupNode =
- NodeMachine.getClosestNode(plr->v.origin, NODE_ZONE, plr);
-
- // Help this player
- if (iBackupNode > -1) {
-
- unstood = true;
-
- BotPointer->rprint("Setting goal for backup");
- BotPointer->setGoalNode(iBackupNode);
- BotPointer->forgetPath();
- BotPointer->f_camp_time = gpGlobals->time - 1;
- BotPointer->f_walk_time = gpGlobals->time;
- }
- }
- // Enemy Down!
- if (strstr(message, "#Enemy_down") != NULL) {
-
- unstood = true;
- can_do_negative = false;
- }
- // Stick together team!
- if (strstr(message, "#Stick_together_team") != NULL) {
- unstood = true;
- // TODO: Find someone to follow. (to stick with)
- }
- // cover me|| strstr (message, "#Cover_me") != NULL
-
- // Need backup / taking fire...
- if (strstr(message, "#Need_backup") != NULL || strstr(message, "#Taking_fire") != NULL) {
-
- unstood = true;
-
- // get source of backup
- int iBackupNode = NodeMachine.getClosestNode(plr->v.origin, NODE_ZONE, plr);
-
- if (iBackupNode > -1) {
- BotPointer->rprint("Setting goal for backup");
- BotPointer->setGoalNode(iBackupNode);
- BotPointer->forgetPath();
- BotPointer->f_camp_time = gpGlobals->time - 1;
- BotPointer->f_walk_time = gpGlobals->time;
- }
- }
-
- // Taking fire!
- if (strstr(message, "#Taking_fire") != NULL) {
- // todo todo todo backup our friend
- // unstood = true;
- }
- // Team fall back!
- if (strstr(message, "#Team_fall_back") != NULL) {}
- // Go GO Go, stop camping, stop following, get the heck out of there!
- if (strstr(message, "#Go_go_go") != NULL) {
- unstood = true;
- BotPointer->f_camp_time = gpGlobals->time - 30;
- BotPointer->f_cover_time = gpGlobals->time - 10;
- BotPointer->f_hold_duck = gpGlobals->time - 10;
- BotPointer->f_jump_time = gpGlobals->time - 10;
- BotPointer->forgetPath();
- BotPointer->forgetGoal();
- }
-
- if ((FUNC_DoRadio(BotPointer)) && (unstood)) {
- if (BotPointer->console_nr == 0
- && radios < (gpGlobals->maxClients / 4)) {
- if (!report_back) {
- UTIL_BotRadioMessage(BotPointer, 3, "1", ""); // Roger that!
- } else {
- UTIL_BotRadioMessage(BotPointer, 3, "6", ""); // Reporting in!
- }
-
- BotPointer->f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.8, 2.0);
- radios++;
- }
- }
- } // they even listen to the radio command?
- else {
- /*
- // filter out the commands where we cannot reply with negative
- // You take the point!
- if (strstr (message, "#You_take_the_point") != NULL)
- can_do_negative = false;
-
- // Enemy Sotted!
- if (strstr (message, "#Enemy_spotted") != NULL)
- can_do_negative = false;
-
- // Enemy Down!
- if (strstr (message, "#Enemy_down") != NULL)
- can_do_negative = false;
-
- if ((FUNC_DoRadio(BotPointer))
- && (unstood) && (can_do_negative))
-
- {
- if (BotPointer->console_nr == 0
- && radios < (gpGlobals->maxClients / 4))
-
- {
- if (report_back == false)
-
- {
- UTIL_BotRadioMessage (BotPointer, 3, "8", ""); // Negative!
- BotPointer->f_console_timer = gpGlobals->time + RANDOM_FLOAT (0.8, 2.0);
- radios++;
- }
- }
- }
- */
- }
- } // End check!
- } // If (Player)
- } // FOR Clients
- return true;
-}
-
-// Is entity visible? (from Entity view)
-bool EntityIsVisible(edict_t *pEntity, Vector dest) {
-
- //DebugOut("bot: EntityIsVisible()\n");
- TraceResult tr;
-
- // trace a line from bot's eyes to destination...
- UTIL_TraceLine(pEntity->v.origin + pEntity->v.view_ofs, dest,
- dont_ignore_monsters, pEntity->v.pContainingEntity, &tr);
-
- // check if line of sight to object is not blocked (i.e. visible)
- if (tr.flFraction >= 1.0)
- return true;
-
- else
- return false;
-}
-
-// Can see Edict?
-bool cBot::canSeeEntity(edict_t *pEntity) {
- if (pEntity == NULL) return false;
-
- TraceResult tr;
- Vector start = pEdict->v.origin + pEdict->v.view_ofs;
- Vector vDest = pEntity->v.origin;
-
- // trace a line from bot's eyes to destination...
- UTIL_TraceLine(start, vDest, ignore_monsters, pEdict->v.pContainingEntity, &tr);
-
- // it hit anything
- if (tr.flFraction < 1.0) {
- // if it hit the entity we wanted to see, then its ok!
- if (tr.pHit == pEntity) return true;
- return false;
- }
-
- return true;
-}
-
-/**
- * Returns distance from this bot to a given nodeIndex. If the given NodeIndex is invalid, the distance returned is 0.
- * @param nodeIndex
- * @return
- */
-float cBot::getDistanceTo(int nodeIndex) {
- tNode *nodePtr = NodeMachine.getNode(nodeIndex);
- if (nodePtr != NULL) {
- return getDistanceTo(nodePtr->origin);
- }
- rprint("getDistanceTo(int nodeIndex)", "The given nodeIndex was invalid, returning 9999 distance");
- return 9999;
-}
-
-/**
- * Returns distance from this bot position (pEdict->v.origin) to given Vector.
- * @param vDest
- * @return
- */
-float cBot::getDistanceTo(Vector vDest) {
- return func_distance(pEdict->v.origin, vDest);
-}
-
-bool cBot::isUsingHostage(edict_t *pHostage) {
- if (pHostage == NULL) return false;
-
- // checks if the current pEdict is already 'in use'
- // note: time check only when we have an hostage pointer assigned
- if (hostage1 == pHostage) {
- rprint("isUsingHostage", "hostage1");
- return true;
- }
-
- if (hostage2 == pHostage) {
- rprint("isUsingHostage", "hostage2");
- return true;
- }
-
- if (hostage3 == pHostage) {
- rprint("isUsingHostage", "hostage3");
- return true;
- }
-
- if (hostage4 == pHostage) {
- rprint("isUsingHostage", "hostage4");
- return true;
- }
-
- return false;
-}
-
-void cBot::forgetHostage(edict_t *pHostage) {
- // these are the hostages we are rescueing (ie, they are following this bot)
- if (hostage1 == pHostage) {
- rprint("forgetHostage", "hostage1");
- hostage1 = NULL;
- }
- if (hostage2 == pHostage) {
- rprint("forgetHostage", "hostage2");
- hostage2 = NULL;
- }
- if (hostage3 == pHostage) {
- rprint("forgetHostage", "hostage3");
- hostage3 = NULL;
- }
- if (hostage4 == pHostage) {
- rprint("forgetHostage", "hostage4");
- hostage4 = NULL;
- }
-
- // this is the hostage we have taken interest in
- if (pBotHostage == pHostage) {
- rprint("forgetHostage", "pBotHostage");
- pBotHostage = NULL;
- }
-}
-
-int cBot::getAmountOfHostagesBeingRescued() {
- int count = 0;
-
- if (hostage1 != NULL) count++;
- if (hostage2 != NULL) count++;
- if (hostage3 != NULL) count++;
- if (hostage4 != NULL) count++;
-
- return count;
-}
-
-// Will return true when the vector is visible.
-// TODO: Make this function more flexible, ie able to hit an entity that it searches
-// and return true on that as well. (mix it with the above function)
-bool cBot::canSeeVector(Vector vDest) {
- TraceResult tr;
- Vector start = pEdict->v.origin + pEdict->v.view_ofs;
-
- // trace a line from bot's eyes to destination...
- UTIL_TraceLine(start, vDest, ignore_monsters, pEdict->v.pContainingEntity, &tr);
-
- if (tr.flFraction < 1.0)
- return false;
-
- return true;
-}
-
-// The coming 2 shield functions where originaly created by Whistler;
-// i got them from the JoeBot source though. But... in the end, thank you
-// Whistler!
-bool cBot::hasShield() {
- // Adapted from Wei Mingzhi's YAPB
- return (strncmp(STRING(pEdict->v.viewmodel), "models/shield/v_shield_", 23) == 0);
-}
-
-bool cBot::hasShieldDrawn() {
- // Adapted from Wei Mingzhi's YAPB
- if (!hasShield())
- return false;
-
- return (pEdict->v.weaponanim == 6 || pEdict->v.weaponanim == 7);
-}
-
-/*
- BotThink()
- This function is the very general/main/simplified thinking function of the bot.
- Do NOT add/remove/change code here! If you want to give the bot information to
- work with. Put it in UpdateStatus(). When the bot has to think about it, do it
- int Think() and everything else (when all is set, how to 'do' it) in Act().
- */
-void BotThink(cBot *pBot) {
- // STEP 1: Update status
- pBot->UpdateStatus();
-
- // STEP 2: Think
- pBot->Think();
-
- // STEP 3: Act
- pBot->Act();
-
- // PASS THROUGH ENGINE
-
-// float frameInterval = m_lastCommandTime - gpGlobals->time;
- float msecval = (gpGlobals->time - pBot->fLastRunPlayerMoveTime) * 1000.0f;
- pBot->fLastRunPlayerMoveTime = gpGlobals->time;
-
- double upMove = 0.0;
- char msg[255];
- sprintf(msg, "moveSpeed %f, strafeSpeed %f, msecVal %f", pBot->f_move_speed, pBot->f_strafe_speed, msecval);
- pBot->rprint_trace("BotThink/pfnRunPlayerMove", msg);
- g_engfuncs.pfnRunPlayerMove(pBot->pEdict,
- pBot->vecMoveAngles,
- pBot->f_move_speed,
- pBot->f_strafe_speed,
- upMove,
- pBot->pEdict->v.button,
- 0,
- msecval);
-
- float fUpdateInterval = 1.0f / 60.0f; // update at 60 fps
- pBot->fUpdateTime = gpGlobals->time + fUpdateInterval;
-}
-
-// 17/07/04
-// log important variables of the bot (it will be called from dll.cpp once per active bot)
-// they are logged into reallog.txt file
-
-void cBot::Dump(void) {
- char buffer[181];
- int iCurrentNode =
- NodeMachine.getClosestNode(pEdict->v.origin, (NODE_ZONE * 2), pEdict);
-
- _snprintf(buffer, 180,
- "%s (#%d %s): timers, now= %.0f, c4_time=%.0f, camp_time=%.0f, wait_time=%.0f, cover_time=%.0f, wander=%.0f, MoveToNodeTime=%.0f\n",
- name, iBotIndex, (iTeam == 1) ? "T" : "CT", gpGlobals->time,
- f_c4_time, f_camp_time, f_wait_time, f_cover_time, fWanderTime,
- fMoveToNodeTime);
- rblog(buffer);
- _snprintf(buffer, 180, " GoalNode=%d, CurrentNode=%d, iPathFlags=",
- iGoalNode, iCurrentNode);
- switch (iPathFlags) {
- case PATH_NONE:
- strncat(buffer, "PATH_NONE ", 180);
- break;
- case PATH_DANGER:
- strncat(buffer, "PATH_DANGER ", 180);
- break;
- case PATH_CONTACT:
- strncat(buffer, "PATH_CONTACT ", 180);
- break;
- case PATH_CAMP:
- strncat(buffer, "PATH_CAMP ", 180);
- break;
- default:
- strncat(buffer, "???", 180);
- }
- strncat(buffer, "\n", 180);
- rblog(buffer);
- if (iGoalNode >= 0)
- NodeMachine.dump_path(iBotIndex, pathIndex);
-}
-
-/**
- * Will begin walk the path by setting pathNodeIndex to 0, which is a valid nr so that
- * isWalkingPath returns true.
- */
-void cBot::beginWalkingPath() {
- this->pathIndex = 0;
-}
-
-bool cBot::hasHostageToRescue() {
- return pBotHostage != NULL;
-}
-
-bool cBot::canSeeHostageToRescue() {
- return canSeeEntity(pBotHostage);
-}
-
-void cBot::clearHostageToRescueTarget() {
- rprint_trace("clearHostageToRescueTarget", "clearing pBotHostage pointer");
- this->pBotHostage = NULL;
-}
-
-// Finds a free hostage pointer and assigns it.
-void cBot::rememberHostageIsFollowingMe(edict_t *pHostage) {
- if (pHostage == NULL) {
- rprint_trace("rememberHostageIsFollowingMe", "ERROR assigning NULL pHostage pointer!?");
- }
- if (hostage1 == NULL) {
- rprint_trace("rememberHostageIsFollowingMe", "hostage1 slot is free.");
- hostage1 = pHostage;
- } else if (hostage2 == NULL) {
- rprint_trace("rememberHostageIsFollowingMe", "hostage2 slot is free.");
- hostage2 = pHostage;
- } else if (hostage3 == NULL) {
- rprint_trace("rememberHostageIsFollowingMe", "hostage3 slot is free.");
- hostage3 = pHostage;
- } else if (hostage4 == NULL) {
- rprint_trace("rememberHostageIsFollowingMe", "hostage4 slot is free.");
- hostage4 = pHostage;
- }
-}
-
-void cBot::checkIfHostagesAreRescued() {
- if (isHostageRescued(this, hostage1)) forgetHostage(hostage1);
- if (isHostageRescued(this, hostage2)) forgetHostage(hostage2);
- if (isHostageRescued(this, hostage3)) forgetHostage(hostage3);
- if (isHostageRescued(this, hostage4)) forgetHostage(hostage4);
-}
-
-bool cBot::isOnSameTeamAs(cBot *pBot) {
- if (pBot == NULL) return false;
- return pBot->iTeam == this->iTeam;
-}
-
-bool cBot::wantsToBuyStuff() {
- return buy_secondary == true ||
- buy_primary == true ||
- buy_ammo_primary == true ||
- buy_ammo_secondary == true ||
- buy_armor == true ||
- buy_defusekit == true ||
- buy_grenade == true ||
- buy_flashbang > 0;
-}
-
-bool cBot::isUsingConsole() {
- return console_nr > 0;
-}
-
-bool cBot::shouldBeAbleToMove() {
- return !isDead() &&
- !isFreezeTime() &&
- !shouldCamp() &&
- !shouldWait() &&
- !shouldActWithC4();
-// !isDucking() &&
-// !isJumping();
-}
-
-edict_t *cBot::getEntityBetweenMeAndCurrentPathNodeToHeadFor() {
- TraceResult tr;
- Vector vOrigin = pEdict->v.origin;
-
- tNode *node = NodeMachine.getNode(getCurrentPathNodeToHeadFor());
-
- //Using TraceHull to detect de_aztec bridge and other entities.
- //DONT_IGNORE_MONSTERS, we reached it only when there are no other bots standing in our way!
- //UTIL_TraceHull(vOrigin, vNode, dont_ignore_monsters, point_hull, pBot->pEdict, &tr);
- //UTIL_TraceHull(vOrigin, vNode, dont_ignore_monsters, human_hull, pBot->pEdict, &tr);
- UTIL_TraceHull(vOrigin, node->origin, dont_ignore_monsters, head_hull, pEdict, &tr);
-
- // if nothing hit (else a wall is in between and we don't care about that):
- if (tr.flFraction < 1.0) {
- if (tr.pHit) {
- return tr.pHit;
- }
- }
-
- return NULL;
-}
-
-/**
- * Get distance to the next node we're heading for
- * @return
- */
-float cBot::getDistanceToNextNode() {
- tNode *node = NodeMachine.getNode(getCurrentPathNodeToHeadFor());
- if (node) {
- return getDistanceTo(node->origin);
- }
- return MAP_MAX_SIZE;
-}
-
-void cBot::setBodyToNode(int nodeIndex) {
- tNode *node = NodeMachine.getNode(nodeIndex);
- if (node) {
- vBody = node->origin;
- }
-}
-
-void cBot::lookAtNode(int nodeIndex) {
- tNode *node = NodeMachine.getNode(nodeIndex);
- if (node) {
- vHead = node->origin;
- }
-}
-
-/**
- * Sets timer to allow movement to node, when timer expires we will think about severing the connection
- * we used.
- * @param timeInSeconds
- */
-void cBot::setTimeToMoveToNode(float timeInSeconds) {
- char msg[255];
- float endTime = gpGlobals->time + timeInSeconds;
- sprintf(msg, "Set to %f so results into end time of %f", timeInSeconds, endTime);
- rprint_trace("setTimeToMoveToNode", msg);
-
- this->nodeTimeIncreasedAmount = 0;
- this->fMoveToNodeTime = endTime;
-}
-
-/**
- * Whatever was set, increase the time given in function param. This expands the time a bit.
- * @param timeInSeconds
- */
-void cBot::increaseTimeToMoveToNode(float timeInSeconds) {
- if (nodeTimeIncreasedAmount < 2) {
- nodeTimeIncreasedAmount++;
- this->fMoveToNodeTime += timeInSeconds;
- float timeToMoveToNodeRemaining = getMoveToNodeTimeRemaining();
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "increaseTimeToMoveToNode with %f for the %d time, making time to move to node remaining %f.", timeInSeconds, nodeTimeIncreasedAmount, timeToMoveToNodeRemaining);
- rprint_trace("increaseTimeToMoveToNode", msg);
- } else {
- rprint_trace("increaseTimeToMoveToNode", "Refused to increase time");
- }
-}
-
-float cBot::getMoveToNodeTimeRemaining() {
- return fMoveToNodeTime - gpGlobals->time;
-}
-
-bool cBot::shouldCamp() {
- return f_camp_time > gpGlobals->time;
-}
-
-bool cBot::shouldWait() {
- return f_wait_time > gpGlobals->time;
-}
-
-void cBot::setTimeToWait(float timeInSeconds) {
- this->f_wait_time = gpGlobals->time + timeInSeconds;
-}
-
-bool cBot::shouldBeAbleToInteractWithButton() {
- return fButtonTime < gpGlobals->time;
-}
-
-bool cBot::hasButtonToInteractWith() {
- return pButtonEdict != NULL;
-}
-
-bool cBot::hasCurrentNode() {
- return iCloseNode > -1;
-}
-
-/**
- * Shorthand method for creating path with flags PATH_NONE.
- * @param destinationNode
- * @return
- */
-bool cBot::createPath(int destinationNode) {
- return createPath(destinationNode, PATH_NONE);
-}
-
-/**
- * Attempts to create a path from current node to destination. Returns true on success, false on failure.
- * @param destinationNode
- * @param flags
- * @return
- */
-bool cBot::createPath(int destinationNode, int flags) {
- if (destinationNode < 0 || destinationNode >= MAX_NODES) {
- rprint("createPath()", "Unable to create path because destination node provided is < 0 or > MAX_NODES");
- return false;
- }
-
- int currentNode = getCurrentNode();
- if (currentNode < 0) {
- rprint("createPath()", "Unable to create path to destination because I am not close to a start node");
- return false;
- }
-
- forgetPath();
-
- char msg[255];
- memset(msg, 0, sizeof(msg));
- sprintf(msg, "Creating path from currentNode [%d] to destination node [%d]", currentNode, destinationNode);
- rprint("createPath()", msg);
-
- return NodeMachine.createPath(currentNode, destinationNode, iBotIndex, this, flags);
-}
-
-void cBot::doDuck() {
- UTIL_BotPressKey(this, IN_DUCK);
- this->f_hold_duck = gpGlobals->time + 0.5;
-
- this->increaseTimeToMoveToNode(0.5);
-}
-
-bool cBot::isDucking() {
- bool b = keyPressed(IN_DUCK) || this->f_hold_duck > gpGlobals->time;
- if (b) {
- rprint_trace("isDucking", "Yes I am ducking");
- }
- return b;
-}
-
-void cBot::doJump(Vector &vector) {
- rprint_trace("doJump", "With vector");
- // stay focussed with body and head to this vector
- this->vHead = vector;
- this->vBody = vector;
-
- doJump();
-}
-
-void cBot::doJump() {
- rprint_trace("doJump", "no vector");
- UTIL_BotPressKey(this, IN_JUMP);
- this->f_jump_time = gpGlobals->time + 0.5;
-
- // duck like this, because doDuck increases node time *again*, so no
- UTIL_BotPressKey(this, IN_DUCK); // DUCK jump by default
- this->f_hold_duck = gpGlobals->time + 0.5;
-
- this->increaseTimeToMoveToNode(0.75);
-}
-
-bool cBot::isJumping() {
- bool b = keyPressed(IN_JUMP) || f_jump_time > gpGlobals->time;
- if (b) {
- rprint_trace("isJumping", "Yes I am jumping");
- }
- return b;
-}
-
-// $Log: bot.cpp,v $
-// Revision 1.21 2004/09/07 18:23:02 eric
-// - bumped version to 3061
-// - adding Frashman code to buy the weapon as selected by Josh's code
-// - Realbot is really the result of multiple people :-)
-//
-// Revision 1.20 2004/09/07 15:44:34 eric
-// - bumped build nr to 3060
-// - minor changes in add2 (to add nodes for Bsp2Rbn utilities)
-// - if compiled with USE_EVY_ADD, then the add2() function is used when adding
-// nodes based on human players instead of add()
-// - else, it now compiles mostly without warnings :-)
-//
-// Revision 1.19 2004/08/07 18:42:56 eric
-// - bumped version to 3058
-// - added a cNodeMachine::add2 which should do the same job as ::add
-// but it seems to work better. ::add2 is used by Bsp2Rbn only for now.
-// - added the display of node flags (water, ladder, jump) next to the
-// node position in 'debug nodes draw'
-// - suppress the debugging information which displayed the hit entity
-// while establishing neighbourhood
-//
-// Revision 1.18 2004/07/30 15:02:29 eric
-// - jumped to version 3057
-// - improved readibility (wapen_tabel -> weapons_table) :-P
-// - all Josh Borke modifications to the buying stuff:
-// * using a switch() instead of several if
-// * better buying code for shield and primary weapons
-// * new command 'debug pistols 0/1'
-//
-// Revision 1.16 2004/07/17 21:32:01 eric
-// - bumped version to 3055
-// - handling of es_ and as_ maps with new goals
-// - added two debug commands:
-// realbot debug goals
-// realbot debug bots
-// - added two nodes commands (for dedicated servers mainly)
-// realbot nodes connect n1 n2
-// realbot nodes disconnect n1 n2
-// - slight modification in goal scoring (only reduced score when two bots of
-// the SAME team select the same goal)
-//
-// Revision 1.15 2004/07/03 15:58:54 eric
-// nova test comment for erics account
-//
-// Revision 1.14 2004/07/02 16:43:35 stefan
-// - upped to build 3051
-// - changed log() into rblog()
-// - removed BOT.CFG code that interpets old RB V1.0 commands
-// - neater respons of the RealBot console
-// - more help from RealBot console (ie, type realbot server broadcast ... with no arguments it will tell you what you can do with this, etc)
-// - removed message "bot personality loaded from file"
-// - in overal; some cleaning done, no extra features added
-//
-// Revision 1.13 2004/07/01 18:09:46 stefan
-// - fixed skill 10 bots not causing memory bugger on re-adding (respawning)
-// - added extra check for respawning bots so auto-add function cannot crash
-// - fixed 2 nitpicks pointed out on the forums
-//
-// Revision 1.12 2004/06/25 07:39:00 stefan
-// - upped to build 3050
-// - fixed reaction time (instant reaction time) bug
-// - added evy's goals, but they are not used yet
-// - fixed some radio responses here and there for swat behaviour.
-// - swat leader automaticly assigned again when one dies
-// - HINT: you can see any changes made by me, by looking at DD/MM/YY - Stefan (ie, 22/06/04 - Stefan, will let you find all changes i made that day)
-//
-// Revision 1.11 2004/06/23 08:24:14 stefan
-// - upped to build 3049
-// - added swat behaviour (team leader assignment, radio response change and leaders command team-mates) - THIS IS EXPERIMENTAL AND DOES NOT ALWAYS WORK AS I WANT IT TO.
-// - changed some conditions in nodemachine
-// - sorry evy, still not added your new goals ;) will do next time, i promise
-//
-// Revision 1.10 2004/06/20 10:24:13 stefan
-// - fixed another steep/stair thingy
-// - changed a bit of the aiming code
-//
-// Revision 1.9 2004/06/19 21:06:14 stefan
-// - changed distance check in nodemachine
-// - fixed some 'steep' bug in nodemachine
-//
-// Revision 1.8 2004/06/17 21:23:23 stefan
-// - fixes several connection problems with nodes. Going down from steep + crates (de_dust) PLUS going up/down from very steep slopes on as_oilrig.. 0wnage and thx to PMB and Evy
-// - fixed chat bug in CS 1.6, its still CS 1.5 & CS 1.6 compatible though
-//
-// Revision 1.7 2004/06/13 20:08:21 stefan
-// - 'bad score for goals' added
-// - bmp dump info (Thanks Evy)
-// - added 'realbot server players', so you can keep a server full at NR players at all times
-// - slightly adjusted goal selection code
-// - wander code disabled
-// - lots of debug info introduced, do not use this source for REAL USAGE!
-//
-// Revision 1.6 2004/06/01 15:30:57 stefan
-// *** empty log message ***
-//
-// Revision 1.5 2004/05/29 19:05:47 stefan
-// - upped to BUILD 3044
-// - removed several debug messages on screen
-// - changed default 'chatrate (max sentences)' to 3
-// - removed copyright notice, which is not valid due GPL license
-//
-// i know, nothing special :)
-//
-// Revision 1.4 2004/05/07 13:33:49 stefan
-// added more comments, more neat code now
-//
-// Revision 1.3 2004/04/18 18:32:36 stefan
-// - Restructured code a bit
-//
-// Revision 1.2 2004/04/18 17:39:19 stefan
-// - Upped to build 2043
-// - REALBOT_PRINT() works properly now
-// - Log() works properly now
-// - Clearing in dll.cpp of reallog.txt at dll init
-// - Logging works now, add REALBOT_PRINT() at every point you want to log something.
-//
+// This is an open source non-commercial project. Dear PVS-Studio, please check it.
+// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
+/**
+ * RealBot : Artificial Intelligence
+ * Version : Work In Progress
+ * Author : Stefan Hendriks
+ * Url : http://realbot.bots-united.com
+ **
+ * DISCLAIMER
+ *
+ * History, Information & Credits:
+ * RealBot is based partially upon the HPB-Bot Template #3 by Botman
+ * Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
+ * Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
+ * everybody else who helped me with this project.
+ * Storage of Visibility Table using BITS by Cheesemonster.
+ *
+ * Some portions of code are from other bots, special thanks (and credits) go
+ * to (in no specific order):
+ *
+ * Pierre Marie Baty
+ * Count - Floyd
+ *
+ * !! BOTS-UNITED FOREVER !!
+ *
+ * This project is open-source, it is protected under the GPL license;
+ * By using this source-code you agree that you will ALWAYS release the
+ * source-code with your project.
+ *
+ **/
+
+
+ /*
+
+ //=========================================================
+ // Returns if enemy can be shoot through some obstacle
+ //=========================================================
+ bool CBaseBot::IsShootableThruObstacle(Vector vecDest)
+ {
+ if (!WeaponShootsThru(m_iCurrentWeapon))
+ return FALSE;
+
+ Vector vecSrc = EyePosition();
+ Vector vecDir = (vecDest - vecSrc).Normalize(); // 1 unit long
+ Vector vecPoint = g_vecZero;
+ int iThickness = 0;
+ int iHits = 0;
+
+ edict_t *pentIgnore = pev->pContainingEntity;
+ TraceResult tr;
+ UTIL_TraceLine(vecSrc, vecDest, ignore_monsters, ignore_glass, pentIgnore, &tr);
+
+ while (tr.flFraction != 1.0 && iHits < 3)
+ {
+ iHits++;
+ iThickness++;
+ vecPoint = tr.vecEndPos + vecDir;
+ while (POINT_CONTENTS(vecPoint) == CONTENTS_SOLID && iThickness < 64)
+ {
+ vecPoint = vecPoint + vecDir;
+ iThickness++;
+ }
+ UTIL_TraceLine(vecPoint, vecDest, ignore_monsters, ignore_glass, pentIgnore, &tr);
+ }
+
+ if (iHits < 3 && iThickness < 64)
+ {
+ if (LengthSquared(vecDest - vecPoint) < 12544)
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "bot.h"
+#include "bot_weapons.h"
+#include "bot_func.h"
+
+#include "game.h"
+#include "NodeMachine.h"
+#include "ChatEngine.h"
+
+#include
+#include
+
+extern edict_t* pHostEdict;
+extern int mod_id;
+extern bool internet_play;
+extern cGame Game;
+extern cNodeMachine NodeMachine;
+extern cChatEngine ChatEngine;
+extern int counterstrike;
+//static FILE *fp;
+extern bool autoskill;
+
+/* Radio issue
+ Credit by Ditlew (NNBOT - Rest In Peace) */
+bool radio_message = false;
+char* message = static_cast(malloc(64 * sizeof(char)));
+char radio_messenger[30];
+
+// random boundries
+extern int random_max_skill;
+extern int random_min_skill;
+cBot bots[32]; // max of 32 bots in a game
+
+// External added variables
+extern bool end_round; // End round
+
+/*#ifndef _WIN32
+#define snprintf std::snprintf //-V1059
+#endif*/
+
+cBot::cBot() {
+ pBotHostage = nullptr;
+ fMoveToNodeTime = -1;
+ clearHostages();
+}
+
+/******************************************************************************
+ Function purpose: Initializes bot vars on spawn
+ ******************************************************************************/
+void cBot::SpawnInit() {
+ rprint_trace("SpawnInit()", "START");
+
+ // ------------------------
+ // TIMERS
+ // ------------------------
+ fUpdateTime = gpGlobals->time;
+ fLastRunPlayerMoveTime = gpGlobals->time - 0.1f;
+ fButtonTime = gpGlobals->time;
+ fChatTime = gpGlobals->time + RANDOM_FLOAT(2.5f, 5.0f);
+ fMemoryTime = gpGlobals->time;
+ fDoRadio = gpGlobals->time;
+ const float freezeTimeCVAR = CVAR_GET_FLOAT("mp_freezetime");
+ fNotStuckTime = gpGlobals->time + freezeTimeCVAR + 0.5f;
+ f_shoot_wait_time = gpGlobals->time;
+ f_goback_time = gpGlobals->time;
+ f_may_jump_time = gpGlobals->time;
+ fCheckHostageStatusTimer = gpGlobals->time;
+ f_defuse = gpGlobals->time;
+ f_allow_keypress = gpGlobals->time;
+ f_use_timer = gpGlobals->time;
+ f_light_time = gpGlobals->time;
+ f_sec_weapon = gpGlobals->time;
+ f_prim_weapon = gpGlobals->time;
+ f_gren_time = gpGlobals->time;
+ f_walk_time = gpGlobals->time;
+ f_hear_time = gpGlobals->time;
+ freezeTime = gpGlobals->time - 1;
+ f_cover_time = gpGlobals->time;
+ f_c4_time = gpGlobals->time;
+ f_update_weapon_time = gpGlobals->time;
+ f_follow_time = gpGlobals->time;
+ f_jump_time = 0.0f;
+ f_hold_duck = gpGlobals->time;
+ f_camp_time = gpGlobals->time;
+ f_wait_time = gpGlobals->time;
+ f_bot_see_enemy_time = gpGlobals->time;
+ f_bot_find_enemy_time = gpGlobals->time;
+ f_shoot_time = gpGlobals->time;
+ fMoveToNodeTime = -1;
+ nodeTimeIncreasedAmount = 0;
+ distanceMovedTimer = gpGlobals->time;
+ distanceMoved = 0;
+ fBlindedTime = gpGlobals->time;
+ f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.1f, 0.9f);
+ fWanderTime = gpGlobals->time;
+ f_strafe_time = gpGlobals->time;
+
+ // Personality Related (these gets changed when loading personality file)
+ fpXOffset = 0.0f;
+ fpYOffset = 0.0f;
+ fpZOffset = 0.0f;
+ fpMinReactTime = 0.0f;
+ fpMaxReactTime = 0.0f;
+
+ // ------------------------
+ // POINTERS
+ // ------------------------
+ pButtonEdict = nullptr;
+ pBotHostage = nullptr;
+ clearHostages();
+ pEnemyEdict = nullptr;
+ pBreakableEdict = nullptr;
+
+ // chat
+ std::memset(chChatSentence, 0, sizeof(chChatSentence));
+
+
+ // ------------------------
+ // INTEGERS
+ // ------------------------
+ iGoalNode = -1;
+ goalIndex = -1;
+ iPreviousGoalNode = -1;
+ iCloseNode = -1;
+ iDiedNode = -1;
+
+ iTeam = -1;
+ bot_class = -1;
+ i_camp_style = 0;
+ iPrimaryWeapon = -1;
+ iSecondaryWeapon = -1;
+ zoomed = ZOOM_NONE;
+ play_rounds = RANDOM_LONG(Game.GetMinPlayRounds(), Game.GetMaxPlayRounds());
+ bot_health = 0;
+ prev_health = 0;
+ bot_armor = 0;
+ bot_weapons = 0;
+ bot_use_special = 0 + RANDOM_LONG(0, 2);
+ console_nr = 0;
+ pathIndex = -1;
+ iPathFlags = PATH_DANGER;
+
+ // Smarter Stuck stuff
+ iDuckTries = 0;
+ iJumpTries = 0;
+
+ // ------------------------
+ // BOOLEANS
+ // ------------------------
+ vip = UTIL_IsVip(pEdict);
+ bWalkKnife = false;
+ buy_ammo_primary = true;
+ buy_ammo_secondary = true;
+ buy_primary = !Game.bPistols; //30/07/04: Josh, handle the pistols only mode
+ buy_secondary = Game.bPistols;
+ buy_armor = false;
+ buy_defusekit = false;
+ bFirstOutOfSight = false;
+ buy_grenade = false;
+ buy_smokegrenade = false;
+ bIssuedInitialRadio = false;
+
+ buy_flashbang = 0;
+ if (RANDOM_LONG(0, 100) < ipWalkWithKnife) {
+ bWalkKnife = true;
+ }
+
+ if (UTIL_GetTeam(pEdict) == 1) {
+ if (RANDOM_LONG(0, 100) < ipBuyDefuseKit) {
+ buy_defusekit = true;
+ }
+ }
+
+ if (RANDOM_LONG(0, 100) < ipBuyGrenade) {
+ buy_grenade = true;
+ }
+
+ // 31.08.04 Frashman added Support for Smoke Grenade
+ if (RANDOM_LONG(0, 100) < ipBuySmokeGren) {
+ buy_smokegrenade = true;
+ }
+
+ if (RANDOM_LONG(0, 100) < ipBuyFlashBang) {
+ buy_flashbang = 2;
+
+ }
+
+ if (RANDOM_LONG(0, 100) < 15 || Game.bPistols)
+ buy_secondary = true;
+
+ // ------------------------
+ // HUD
+ // ------------------------
+ bHUD_C4_plantable = false; // Get's init'ed anyway... // BERKED
+
+ // ------------------------
+ // FLOATS
+ // ------------------------
+ f_strafe_speed = 0.0f;
+ f_max_speed = CVAR_GET_FLOAT("sv_maxspeed");
+
+ // ------------------------
+ // VECTORS
+ // ------------------------
+ prevOrigin = Vector(9999.0, 9999.0, 9999.0);
+ lastSeenEnemyVector = Vector(0, 0, 0);
+ vEar = Vector(9999, 9999, 9999);
+
+ // ------------------------
+ // CHAR
+ // ------------------------
+ arg1[0] = 0;
+ arg2[0] = 0;
+ arg3[0] = 0;
+ std::memset(&(current_weapon), 0, sizeof(current_weapon));
+ std::memset(&(m_rgAmmo), 0, sizeof(m_rgAmmo));
+
+ rprint_trace("SpawnInit()", "END");
+}
+
+/******************************************************************************
+ Function purpose: Initializes bot vars on new round
+ ******************************************************************************/
+void cBot::NewRound() {
+ rprint_trace("NewRound()", "START");
+
+ // ------------------------
+ // TIMERS
+ // ------------------------
+ fUpdateTime = gpGlobals->time;
+ fLastRunPlayerMoveTime = gpGlobals->time;
+ fCheckHostageStatusTimer = gpGlobals->time;
+ fButtonTime = gpGlobals->time;
+ fChatTime = gpGlobals->time + RANDOM_FLOAT(2.5f, 5.0f);
+ fMemoryTime = gpGlobals->time;
+ fDoRadio = gpGlobals->time;
+ const float freezeTimeCVAR = CVAR_GET_FLOAT("mp_freezetime");
+ fNotStuckTime = gpGlobals->time + freezeTimeCVAR + 0.5f;
+ f_shoot_wait_time = gpGlobals->time;
+ f_goback_time = gpGlobals->time;
+ f_may_jump_time = gpGlobals->time;
+ f_defuse = gpGlobals->time;
+ f_allow_keypress = gpGlobals->time;
+ f_use_timer = gpGlobals->time;
+ f_light_time = gpGlobals->time;
+ f_sec_weapon = gpGlobals->time;
+ f_prim_weapon = gpGlobals->time;
+ f_gren_time = gpGlobals->time;
+ f_walk_time = gpGlobals->time;
+ f_hear_time = gpGlobals->time;
+ freezeTime = gpGlobals->time - 1;
+ f_cover_time = gpGlobals->time;
+ f_c4_time = gpGlobals->time;
+ f_update_weapon_time = gpGlobals->time;
+ f_follow_time = gpGlobals->time;
+ f_jump_time = 0.0f;
+ f_hold_duck = gpGlobals->time - 1;
+ f_camp_time = gpGlobals->time;
+ f_wait_time = gpGlobals->time;
+ f_bot_see_enemy_time = gpGlobals->time;
+ f_bot_find_enemy_time = gpGlobals->time;
+ f_shoot_time = gpGlobals->time;
+ fMoveToNodeTime = -1;
+ nodeTimeIncreasedAmount = 0;
+ distanceMovedTimer = gpGlobals->time;
+ distanceMoved = 0;
+ fBlindedTime = gpGlobals->time;
+ f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.1f, 0.9f);
+ fWanderTime = gpGlobals->time;
+ f_strafe_time = gpGlobals->time;
+
+ // ------------------------
+ // POINTERS
+ // ------------------------
+ pButtonEdict = nullptr;
+ pBotHostage = nullptr;
+ clearHostages();
+ pEnemyEdict = nullptr;
+ pBreakableEdict = nullptr;
+
+ // ------------------------
+ // INTEGERS
+ // ------------------------
+ i_camp_style = 0;
+ iPrimaryWeapon = -1;
+ iSecondaryWeapon = -1;
+ zoomed = ZOOM_NONE;
+ bot_health = 0;
+ prev_health = 0;
+ bot_armor = 0;
+ // bot_weapons = 0; // <- stefan: prevent from buying new stuff every round!
+ console_nr = 0;
+ pathIndex = -1;
+ iGoalNode = -1;
+ goalIndex = -1;
+ iPreviousGoalNode = -1;
+ iCloseNode = -1;
+
+
+ // Smarter Stuck stuff
+ iDuckTries = 0;
+ iJumpTries = 0;
+
+ if (RANDOM_LONG(0, 100) < ipFearRate)
+ iPathFlags = PATH_DANGER;
+ else
+ iPathFlags = PATH_NONE;
+
+ // ------------------------
+ // BOOLEANS
+ // ------------------------
+
+ // chat
+ std::memset(chChatSentence, 0, sizeof(chChatSentence));
+
+ vip = UTIL_IsVip(pEdict);
+
+ // Every round consider
+ bWalkKnife = false;
+
+ if (RANDOM_LONG(0, 100) < ipWalkWithKnife)
+ bWalkKnife = true;
+
+ // Buying
+ buy_ammo_primary = true;
+ buy_ammo_secondary = true;
+ buy_primary = !Game.bPistols;
+ buy_grenade = false;
+ buy_smokegrenade = false;
+ buy_flashbang = 0;
+ buy_secondary = Game.bPistols;
+ buy_armor = false;
+ buy_defusekit = false;
+
+ if (UTIL_GetTeam(pEdict) == 1)
+ if (RANDOM_LONG(0, 100) < ipBuyDefuseKit)
+ buy_defusekit = true;
+
+ if (RANDOM_LONG(0, 100) < ipBuyArmour)
+ buy_armor = true;
+
+ if (RANDOM_LONG(0, 100) < ipBuyGrenade)
+ buy_grenade = true;
+
+ if (RANDOM_LONG(0, 100) < ipBuySmokeGren)
+ buy_smokegrenade = true;
+
+ if (RANDOM_LONG(0, 100) < ipBuyFlashBang)
+ buy_flashbang = 2;
+
+
+ bFirstOutOfSight = false;
+ bIssuedInitialRadio = false;
+
+ f_strafe_speed = 0.0f;
+
+ // ------------------------
+ // VECTORS
+ // ------------------------
+ prevOrigin = Vector(9999.0f, 9999.0f, 9999.0f);
+ lastSeenEnemyVector = Vector(0, 0, 0);
+ vEar = Vector(9999, 9999, 9999);
+
+ // ------------------------
+ // CHAR
+ // ------------------------
+ arg1[0] = 0;
+ arg2[0] = 0;
+ arg3[0] = 0;
+
+ // initalize a few other stuff
+ NodeMachine.path_clear(iBotIndex);
+ iPathFlags = PATH_NONE;
+
+ played_rounds++;
+
+ // hello dudes
+ if (played_rounds == 1) {
+ // do some chatting
+ if (RANDOM_LONG(0, 100) < (ipChatRate + 10)) {
+ // we should say something now?
+ int iMax = -1;
+
+ for (const char(&tc)[128] : ChatEngine.ReplyBlock[98].sentence)
+ {
+ if (tc[0] != '\0')
+ iMax++;
+ }
+
+ const int the_c = RANDOM_LONG(0, iMax);
+
+ if (the_c > -1 && iMax > -1) {
+ char chSentence[80] = {};
+ snprintf(chSentence, sizeof(chSentence), "%s ", ChatEngine.ReplyBlock[98].sentence[the_c]);
+ PrepareChat(chSentence);
+ }
+ }
+ }
+
+ clearHostages();
+ clearHostageToRescueTarget();
+
+ rprint("NewRound", "Initialization new round finished");
+}
+
+/******************************************************************************
+ Function purpose: Returns a random chat sentence and stores it into 'sentence'
+ ******************************************************************************/
+void cBot::PrepareChat(char sentence[128]) {
+ if (Game.iProducedSentences <= Game.iMaxSentences) {
+ // makes bot chat away
+ fChatTime = gpGlobals->time + RANDOM_FLOAT(0.1f, 2.0f);
+ std::strcpy(chChatSentence, sentence); // copy this
+ Game.iProducedSentences++;
+ }
+}
+
+/******************************************************************************
+ Function purpose: Return reaction time based upon skill
+ ******************************************************************************/
+float cBot::ReactionTime(const int iSkill) {
+ const float time = RANDOM_FLOAT(fpMinReactTime, fpMaxReactTime);
+ if (Game.messageVerbosity > 1) {
+ char msg[255];
+ snprintf(msg, sizeof(msg), "minReactTime %f, maxReactTime %f, skill %d, results into %f", fpMinReactTime, fpMaxReactTime, iSkill, time);
+ rprint_trace("ReactionTime()", msg);
+ }
+ return time;
+}
+
+/******************************************************************************
+ Function purpose: Finds a (new) enemy
+ ******************************************************************************/
+int cBot::FindEnemy() {
+ // When on ladder, do not search for enemies
+ if (isOnLadder())
+ return -1;
+
+ // When blinded we cannot search for enemies
+ if (fBlindedTime > gpGlobals->time)
+ return -1;
+ float fNearestDistance = 9999; // Nearest distance
+ edict_t* pNewEnemy = nullptr; // New enemy found
+
+ // SEARCH PLAYERS FOR ENEMIES
+ for (int i = 1; i <= gpGlobals->maxClients; i++) {
+ edict_t* pPlayer = INDEXENT(i);
+
+ // skip invalid players and skip self (i.e. this bot)
+ if (pPlayer && !pPlayer->free && pPlayer != pEdict) {
+
+ // skip this player if not alive (i.e. dead or dying)
+ if (!IsAlive(pPlayer))
+ continue;
+
+ Vector vVecEnd = pPlayer->v.origin + pPlayer->v.view_ofs;
+
+ // if bot can see the player...
+ if (FInViewCone(&vVecEnd, pEdict) && FVisible(vVecEnd, pEdict)) {
+ const int player_team = UTIL_GetTeam(pPlayer);
+ const int bot_team = UTIL_GetTeam(pEdict);
+
+ if (player_team == bot_team) {
+ // do not target teammates
+ continue;
+ }
+
+ // It's not a friend, track enemy
+ const float fDistance = (pPlayer->v.origin - pEdict->v.origin).Length();
+ bool bCanSee = true;
+
+ // The further away, the less chance we see this enemy
+ // Uncomment the following lines if you want to add distance-based visibility check
+ // if (RANDOM_FLOAT(0, 1.0) < (fDistance / 4096)) {
+ // bCanSee = false;
+ // }
+
+ // If the bot carries a sniper, always consider the enemy visible
+ if (CarryWeaponType() != SNIPER) {
+ // bCanSee = true;
+ }
+
+ if (fDistance < fNearestDistance && bCanSee) {
+ fNearestDistance = fDistance;
+ pNewEnemy = pPlayer;
+ }
+ }
+ } // valid player
+ } // FOR
+
+ // We found a new enemy & the new enemy is different then previous pointer
+ if (pNewEnemy && pNewEnemy != pEnemyEdict) {
+ const int iCurrentNode = determineCurrentNode();
+
+ // Add 'contact' data
+ if (iCurrentNode > -1) {
+ NodeMachine.contact(iCurrentNode, UTIL_GetTeam(pEdict));
+ }
+
+ // We have a reaction time to this new enemy
+ rememberEnemyFound();
+ f_shoot_time = gpGlobals->time + ReactionTime(bot_skill);
+
+ const bool hadNoEnemy = pEnemyEdict == nullptr;
+ pEnemyEdict = pNewEnemy; // Update pointer
+
+ // We did not have an enemy before
+ if (hadNoEnemy) {
+ rprint_trace("FindEnemy()", "Found new enemy");
+
+ // RADIO: When we found a NEW enemy but NOT via a friend
+ if (FUNC_DoRadio(this)) {
+ UTIL_BotRadioMessage(this, 3, "2", "");
+ }
+
+ // We found a new enemy
+ return 0;
+ }
+
+ // we found an enemy that is newer/more dangerous then previous
+ rprint_trace("FindEnemy()", "Found 'newer' enemy");
+ return 3;
+ }
+
+ // nothing found
+ return -1; // return result
+}
+
+void cBot::rememberEnemyFound() {
+ f_bot_find_enemy_time = gpGlobals->time + REMEMBER_ENEMY_TIME;
+}
+
+/******************************************************************************
+ Function purpose: Sets vHead to aim at vector
+ ******************************************************************************/
+void cBot::setHeadAiming(const Vector& vTarget) {
+ vHead = vTarget;
+}
+
+/**
+ * Returns true / false whether enemy is alive.
+ * @return
+ */
+bool cBot::isEnemyAlive() const
+{
+ return IsAlive(pEnemyEdict);
+}
+
+bool cBot::isSeeingEnemy() {
+ if (!hasEnemy()) {
+ this->rprint("canSeeEnemy called without having enemy?");
+ return false;
+ }
+
+ if (isBlindedByFlashbang()) {
+ return false;
+ }
+ Vector enemyBody = pEnemyEdict->v.origin; // Renamed from vBody to enemyBody - [APG]RoboCop[CL]
+ Vector enemyHead = pEnemyEdict->v.origin + pEnemyEdict->v.view_ofs; // Renamed from vHead to enemyHead
+
+ const bool bodyInFOV = FInViewCone(&enemyBody, pEdict) && FVisible(enemyBody, pEdict);
+ const bool headInFOV = FInViewCone(&enemyHead, pEdict) && FVisible(enemyHead, pEdict);
+ if (bodyInFOV || headInFOV) {
+ return true;
+ }
+ return false;
+}
+
+/******************************************************************************
+ Function purpose: Aims at enemy, only when valid. Based upon skill how it 'aims'
+ ******************************************************************************/
+void cBot::AimAtEnemy() {
+ if (!hasEnemy())
+ return;
+
+ // We cannot see our enemy? -> bail out
+ if (isSeeingEnemy()) {
+ setHeadAiming(lastSeenEnemyVector); // look at last known vector of enemy
+ return;
+ }
+
+ // Distance to enemy
+ const float fDistance = (pEnemyEdict->v.origin - pEdict->v.origin).Length() + 1; // +1 to make sure we never divide by zero
+
+ // factor in distance, the further away the more deviation - which is based on skill
+ const int skillReversed = 10 - bot_skill + 1;
+ float fScale = 0.5f + fDistance / static_cast(64 *
+ skillReversed); // a good skilled bot is less impacted by distance than a bad skilled bot
+
+ if (CarryWeaponType() == SNIPER) fScale *= 0.80f; // sniping improves aiming
+
+ // Set target here
+ Vector vTarget;
+ if (bot_skill <= 1)
+ vTarget = pEnemyEdict->v.origin + pEnemyEdict->v.view_ofs * RANDOM_FLOAT(-0.5f, 1.1f); // aim for the head
+ else if (bot_skill < 4) // bot_skill > 1 is implied here? [APG]RoboCop[CL]
+ vTarget = pEnemyEdict->v.origin +
+ pEnemyEdict->v.view_ofs * RANDOM_FLOAT(-2.5f, 2.5f); // aim for the head more fuzzy
+ else
+ vTarget = pEdict->v.origin; // aim for body
+
+ // Based upon how far, we make this fuzzy
+ float fDy, fDz;
+ float fDx = fDy = fDz = static_cast(bot_skill + 1) * fScale;
+
+ // Example 1:
+ // Super skilled bot (bot_skill 1), with enemy of 2048 units away. Results into:
+ // skillReversed = (10 - 0 + 1) == 11
+ // fScale = 2048 / (128 * 11) -> 2048 / 1408 => 1.454545
+ // fd* = 0.5 + 1 * 1,95
+
+ // Example 2, less skilled bot (skill = 3) same enemy
+ // skillReversed = (10 - 3 + 1) == 8
+ // fScale = 2048 / (128 * 8) -> 2048 / 1024 => 2
+ // fd* = 3 * 2
+
+ vTarget = vTarget + Vector(
+ RANDOM_FLOAT(-fDx, fDx),
+ RANDOM_FLOAT(-fDy, fDy),
+ RANDOM_FLOAT(-fDz, fDz)
+ );
+
+ // Add Offset
+ fDx = fpXOffset;
+ fDy = fpYOffset;
+ fDz = fpZOffset;
+
+ // increase offset with personality x,y,z randomly
+ vTarget = vTarget + Vector(
+ RANDOM_FLOAT(-fDx, fDx),
+ RANDOM_FLOAT(-fDy, fDy),
+ RANDOM_FLOAT(-fDz, fDz)
+ );
+
+ if (isHoldingGrenadeOrFlashbang()) {
+ // aim a bit higher
+ vTarget = vTarget + Vector(0, 0, 50);
+ }
+
+ setHeadAiming(vTarget);
+}
+
+bool cBot::isBlindedByFlashbang() const {
+ return fBlindedTime > gpGlobals->time;
+}
+
+bool cBot::isHoldingGrenadeOrFlashbang() const {
+ return current_weapon.iId == CS_WEAPON_HEGRENADE || current_weapon.iId == CS_WEAPON_FLASHBANG;
+}
+
+/******************************************************************************
+ Function purpose: Perform fighting actions
+ ******************************************************************************/
+void cBot::FightEnemy() {
+ // We can see our enemy
+ if (!isBlindedByFlashbang() && isSeeingEnemy()) {
+
+ // GET OUT OF CAMP MODE
+ f_camp_time = std::min(f_camp_time, gpGlobals->time);
+
+ // Next time our enemy gets out of sight, it will be the 'first' time
+ // of all 'frame times'.
+ bFirstOutOfSight = false;
+
+ // Remember last seen enemy position
+ lastSeenEnemyVector = pEnemyEdict->v.origin; // last seen enemy position
+
+ // FIXME: Fix the darn zoom bug
+ // zoom in with sniper gun
+ if (CarryWeaponType() == SNIPER) {
+ if (zoomed < ZOOM_TWICE && f_allow_keypress < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK2);
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ zoomed++;
+
+ if (zoomed > ZOOM_TWICE)
+ zoomed = ZOOM_NONE;
+ }
+ } else if (FUNC_BotHoldsZoomWeapon(this)) {
+ if (zoomed < ZOOM_ONCE && f_allow_keypress < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK2);
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ zoomed++;
+ }
+ }
+
+ // NOT blinded by flashbang, try to find cover?
+ if (f_cover_time < gpGlobals->time) {
+ // COVER: Not taking cover now, fight using fightstyles.
+
+ // when vip, we always take cover.
+ if (vip) {
+ // Camp, take cover, etc.
+ BOT_DecideTakeCover(this);
+
+ if (FUNC_DoRadio(this)) {
+ UTIL_BotRadioMessage(this, 3, "3", ""); // need backup
+ }
+ } else {
+ // DECIDE: Should we take cover or not.
+ if (FUNC_ShouldTakeCover(this)) {
+ FindCover();
+ }
+ }
+ } else {
+
+ }
+
+ // Keep timer updated for enemy
+ f_bot_find_enemy_time = gpGlobals->time + REMEMBER_ENEMY_TIME;
+ }
+ else // ---- CANNOT SEE ENEMY
+ {
+ if (f_bot_find_enemy_time < gpGlobals->time) {
+ pEnemyEdict = nullptr;
+ lastSeenEnemyVector = Vector(0, 0, 0);
+ rprint_trace("FightEnemy()", "Lost enemy out of sight, forgetting path and goal");
+ forgetPath();
+ forgetGoal();
+ } else {
+
+ // When we have the enemy for the first time out of sight
+ // we calculate a path to the last seen position
+ if (!bFirstOutOfSight) {
+ rprint_trace("FightEnemy()", "Enemy out of sight, calculating path towards it.");
+ // Only change path when we update our information here
+ const int iGoal = NodeMachine.getClosestNode(lastSeenEnemyVector, NODE_ZONE, pEdict);
+ if (iGoal > -1) {
+ setGoalNode(iGoal);
+ forgetPath();
+ }
+
+ bFirstOutOfSight = true;
+ } else {
+ if (!hasGoal()) {
+ rprint("Enemy out of sight and no goal, forgetting enemy");
+ forgetEnemy();
+ }
+ }
+ }
+ } // visible
+}
+
+void cBot::pickWeapon(const int weaponId) {
+ UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(weaponId));
+ f_c4_time = gpGlobals->time - 1; // reset C4 timer data
+ // give Counter-Strike time to switch weapon (animation, update state, etc)
+ f_update_weapon_time = gpGlobals->time + 0.7f;
+}
+
+bool cBot::ownsFavoritePrimaryWeapon() const
+{
+ return hasFavoritePrimaryWeaponPreference() && isOwningWeapon(ipFavoPriWeapon);
+}
+
+bool cBot::ownsFavoriteSecondaryWeapon() const
+{
+ return hasFavoriteSecondaryWeaponPreference() && isOwningWeapon(ipFavoSecWeapon);
+}
+
+/**
+ * Returns true if bot has weapon (id) in possession
+ * @param weaponId
+ * @return
+ */
+bool cBot::isOwningWeapon(const int weaponId) const
+{
+ return bot_weapons & 1 << weaponId;
+}
+
+/**
+ * Returns true if bot carries weapon right now
+ * @param weaponId
+ * @return
+ */
+bool cBot::isHoldingWeapon(const int weaponId) const
+{
+ return current_weapon.iId == weaponId;
+}
+
+bool cBot::hasFavoritePrimaryWeaponPreference() const
+{
+ return ipFavoPriWeapon > -1;
+}
+
+bool cBot::hasFavoriteSecondaryWeaponPreference() const
+{
+ return ipFavoSecWeapon > -1;
+}
+
+bool cBot::canAfford(const int price) const //price muddled with weaponId? [APG]RoboCop[CL]
+{
+ return this->bot_money > price;
+}
+
+/******************************************************************************
+ Function purpose: Based upon several events pick the best weapon
+ ******************************************************************************/
+void cBot::PickBestWeapon() {
+ // does Timer allow to change weapon? (only when f_update_weapon_time < gpGlobals->time
+ if (f_update_weapon_time > gpGlobals->time)
+ return;
+
+ // Distance to enemy
+ const float fDistance = func_distance(pEdict->v.origin, lastSeenEnemyVector);
+
+ constexpr float knifeDistance = 300.0f;
+
+ // ----------------------------
+ // In this function all we do is decide what weapon to pick
+ // if we don't pick another weapon the current weapon is okay
+ // ----------------------------
+
+ // First we handle situations which are bad, no matter the distance
+ // or any other circumstance.
+
+ // BAD: Carrying C4 or knife
+ if (CarryWeapon(CS_WEAPON_C4) || // carrying C4
+ (CarryWeapon(CS_WEAPON_KNIFE) && fDistance > knifeDistance))
+ {
+ // carrying knife and too far
+ if (hasPrimaryWeaponEquiped()) {
+ pickWeapon(iPrimaryWeapon);
+ return;
+ }
+ if (hasSecondaryWeaponEquiped()) {
+ pickWeapon(iSecondaryWeapon);
+ return;
+ }
+ }
+
+ // At this point we do not update weapon information. And we did not 'switch back' to primary / secondary
+ if (hasEnemy() && !isSeeingEnemy()) {
+ // decision to pull HE grenade
+ if (isOwningWeapon(CS_WEAPON_HEGRENADE) && // we have a grenade
+ func_distance(pEdict->v.origin, lastSeenEnemyVector) < 900 && // we are close
+ func_distance(pEdict->v.origin, lastSeenEnemyVector) > 200 && // but not to close
+ RANDOM_LONG(0, 100) < 10 && // only randomly we pick a grenade in the heat of the battle
+ current_weapon.iId != CS_WEAPON_HEGRENADE && current_weapon.iId != CS_WEAPON_FLASHBANG &&
+ f_gren_time + 15.0f < gpGlobals->time) // and dont hold it yet
+ {
+ UTIL_SelectItem(pEdict, "weapon_hegrenade"); // select grenade
+ f_wait_time = gpGlobals->time + 1.0f; // wait 1 second (stand still 1 sec)
+ f_gren_time =
+ gpGlobals->time + (1.0f + RANDOM_FLOAT(0.5f, 1.5f)); // and determine how long we should hold it
+ zoomed = ZOOM_NONE; // Counter-Strike resets zooming when choosing another weapon
+ return;
+ }
+ // OR we pull a flashbang?
+ if (isOwningWeapon(CS_WEAPON_FLASHBANG) && // we have a grenade
+ func_distance(pEdict->v.origin, lastSeenEnemyVector) < 200 && // we are close
+ func_distance(pEdict->v.origin, lastSeenEnemyVector) > 300 && // but not to close
+ RANDOM_LONG(0, 100) < 15 && // only randomly we pick a grenade in the heat of the battle
+ current_weapon.iId != CS_WEAPON_FLASHBANG && current_weapon.iId != CS_WEAPON_HEGRENADE &&
+ f_gren_time + 15 < gpGlobals->time) // and dont hold it yet
+ {
+ UTIL_SelectItem(pEdict, "weapon_flashbang"); // select grenade
+ f_wait_time = gpGlobals->time + 1.0f; // wait 1 second (stand still 1 sec)
+ f_gren_time =
+ gpGlobals->time + (1.0f + RANDOM_FLOAT(0.5f, 1.5f)); // and determine how long we should hold it
+ zoomed = ZOOM_NONE; // Counter-Strike resets zooming when choosing another weapon
+ return;
+ }
+ }
+
+ // When we are here, we did not decide to switch to grenade/flashbang. Now we look
+ // if the bot has to reload or switch weapon based upon ammo.
+
+ // ----------------------------------------
+ // More complex bad things that can happen:
+ // ----------------------------------------
+ const int iTotalAmmo = current_weapon.iAmmo1;
+ const int iCurrentAmmo = current_weapon.iClip;
+
+ //char msg[80];
+ //sprintf(msg, "BOT: ICLIP %d, TOTALAMMO %d\n", iCurrentAmmo, iTotalAmmo);
+
+ // Clip is out of ammo
+ if (iCurrentAmmo < 1
+ && (CarryWeaponType() == PRIMARY || CarryWeaponType() == SECONDARY)) {
+ // Camp, take cover, etc.
+ BOT_DecideTakeCover(this);
+
+ // We still have ammo!
+ if (iTotalAmmo > 0) {
+ UTIL_BotPressKey(this, IN_RELOAD);
+ f_update_weapon_time = gpGlobals->time + 0.7f; // update timer
+ // return;
+ } else {
+ // Thanks to dstruct2k for easy ctrl-c/v, i optimized the code
+ // a bit though. Btw, distance 600 is too far for slashing :)
+
+ // at here the bot does not have ammo of the current weapon, so
+ // switch to another weapon.
+ if (iPrimaryWeapon > -1 && // we have a primary
+ current_weapon.iId != iPrimaryWeapon && // that's not the current, empty gun
+ func_distance(pEdict->v.origin, lastSeenEnemyVector) > 300) // and we are not close enough to knife
+ {
+ // select primary weapon
+ UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iPrimaryWeapon)); // select the primary
+ //return;
+ } else {
+
+ if (iSecondaryWeapon > -1 && current_weapon.iId != iSecondaryWeapon &&
+ // that's not the current, empty gun
+ func_distance(pEdict->v.origin, lastSeenEnemyVector) > 300) // and we are not close enough to knife
+ {
+ UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iSecondaryWeapon)); // select the secondary
+ //return;
+ } else {
+ if (isOwningWeapon(CS_WEAPON_KNIFE) && // we have a knife (for non-knife maps)
+ !isHoldingWeapon(CS_WEAPON_KNIFE)) // but we do not carry it
+ {
+ UTIL_SelectItem(pEdict, "weapon_knife");
+ //return;
+ }
+ }
+ } // end if
+ } // no ammo
+ }
+}
+
+/******************************************************************************
+ Function purpose: Fire weapon (burst; or do not fire when not allowed)
+ ******************************************************************************/
+void cBot::FireWeapon() {
+ // We may not shoot!
+ if (f_shoot_time > gpGlobals->time ||
+ f_update_weapon_time > gpGlobals->time)
+ return;
+
+ if (pBreakableEdict == nullptr && !isSeeingEnemy()) {
+ return;
+ }
+
+ // ------------------------------------------------------------
+ float fDistance = 50.0f;
+
+ if (hasEnemy()) {
+ fDistance = func_distance(pEdict->v.origin, pEnemyEdict->v.origin);
+ }
+ else if (pBreakableEdict != nullptr) {
+ fDistance = func_distance(pEdict->v.origin, VecBModelOrigin(pBreakableEdict));
+ }
+
+ // Depending on weapon type
+ if (CarryWeaponType() == SECONDARY) {
+ // We may shoot, use shooting rate.
+ // TODO TODO TODO; Add shooting rates in BUYTABLE.INI
+
+ if (f_sec_weapon < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK);
+ f_sec_weapon = gpGlobals->time + RANDOM_FLOAT(0.05f, 0.2f);
+ }
+
+ } else if (CarryWeaponType() == PRIMARY) {
+ // We may shoot, use shooting rate.
+ // TODO TODO TODO: Add shooting rates in BUYTABLE.INI
+ if (f_prim_weapon < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
+ // All other weapons, the more distance, the more time we add to holding weapon
+ if (f_shoot_wait_time < gpGlobals->time) {
+ // AK, COLT, STEYR AUG, SIG SG552 only when enough skill!
+ if ((CarryWeapon(CS_WEAPON_AK47) || CarryWeapon(CS_WEAPON_M4A1)
+ || CarryWeapon(CS_WEAPON_SG552) || CarryWeapon(CS_WEAPON_AUG))
+ && bot_skill < 3) {
+ float f_burst = (2048 / fDistance) + 0.1f;
+ f_burst = std::max(f_burst, 0.1f);
+ f_burst = std::min(f_burst, 0.4f);
+
+ // CS 1.6 less burst
+ if (counterstrike == 1)
+ f_burst = std::min(f_burst, 0.3f);
+
+ f_prim_weapon = gpGlobals->time + f_burst;
+
+ f_shoot_wait_time = gpGlobals->time + (f_burst * 3);
+ } else // other weapons
+ {
+ float f_burst = 0.1f;
+ if (fDistance > 300 && bot_skill < 6) {
+ f_burst = (fDistance - 300) / 550;
+ if (f_burst < 0.1f)
+ f_burst = 0.0f;
+ f_burst = std::min(f_burst, 0.7f);
+
+ // CS 1.6 less burst
+ if (counterstrike == 1)
+ f_burst = std::min(f_burst, 0.2f);
+ if (f_prim_weapon < gpGlobals->time)
+ f_prim_weapon = gpGlobals->time + f_burst;
+ }
+ f_shoot_wait_time =
+ gpGlobals->time + f_burst + RANDOM_FLOAT(0.2f, 0.7f);
+ }
+ }
+ } // give the bot alteast 0.3 seconds to fire its weapon
+ } // PRIMARY
+ else if (CarryWeaponType() == GRENADE) {
+ if (f_gren_time > gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
+ setMoveSpeed(f_max_speed / 2);
+
+ // Set new goal when holding flashbang!
+ if (current_weapon.iId == CS_WEAPON_FLASHBANG) {
+
+ //tonode ?
+ // COVER: Take cover, using tracelines all the time!
+ FindCover();
+ }
+ } else if (f_gren_time + 0.5f < gpGlobals->time) {
+ // NOTE: Should not happen, a bot cannot 'forget' this...
+ f_gren_time = gpGlobals->time + 1;
+ }
+ } // GRENADE
+ else if (CarryWeaponType() == KNIFE) {
+ setMoveSpeed(f_max_speed);
+ UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
+ } // KNIFE
+ else if (CarryWeaponType() == SNIPER) {
+ setMoveSpeed(f_max_speed / 2);
+ UTIL_BotPressKey(this, IN_ATTACK); // Hold fire
+ f_shoot_time = gpGlobals->time + 1.0f;
+ } // SNIPER
+ else if (CarryWeaponType() == SHIELD) {
+ if (fDistance > 550) {
+ if (hasShieldDrawn()) {
+ // when the enemy is far away, we keep it
+ } else {
+ // draw shield!
+ UTIL_BotPressKey(this, IN_ATTACK2); // secondary attack makes shield draw
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ }
+ } else {
+ // get weapon here.
+ if (hasShieldDrawn() && f_allow_keypress < gpGlobals->time) {
+ rblog
+ ("BOT: Enemy is close enough, i should withdraw shield to attack this enemy\n");
+ UTIL_BotPressKey(this, IN_ATTACK2);
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ }
+ }
+ } else {
+ // debug print
+ REALBOT_PRINT(this, "FireWeapon()", "Unknown weapon");
+ }
+}
+
+/******************************************************************************
+ Function purpose: The combat brain of the bot ( called by Think() )
+ ******************************************************************************/
+void cBot::Combat() {
+ if (pBreakableEdict != nullptr) {
+ FUNC_AttackBreakable(this);
+ return;
+ }
+
+ if (!hasEnemy()) {
+ rprint("Unexpected call to Combat because bot has no enemy!");
+ return;
+ }
+
+ // Bot is on ladder
+ if (isOnLadder()) {
+ // When on a ladder, the bot is vulnerable.
+ // It should stop moving and try to fight back if it can see the enemy.
+ stopMoving();
+
+ if (isSeeingEnemy()) {
+ // Switch to a pistol if available, as it's more accurate on ladders.
+ if (hasSecondaryWeaponEquiped() && CarryWeaponType() != SECONDARY) {
+ pickWeapon(iSecondaryWeapon);
+ }
+
+ // Aim and fire at the enemy.
+ AimAtEnemy();
+ FireWeapon();
+ }
+
+ // Do not proceed with normal ground combat logic.
+ return;
+ }
+
+ // We have an enemy and it is now dead
+ if (!isEnemyAlive()) {
+
+ // radio (Enemy down)
+ if (FUNC_DoRadio(this)) {
+ UTIL_BotRadioMessage(this, 3, "9", "");
+ }
+
+ // get bot pointer
+ const cBot* checkpointer = UTIL_GetBotPointer(pEnemyEdict);
+
+ // This bot killed a human; adjust skill when 'autoskill' is on.
+ if (checkpointer == nullptr) {
+
+ // increase bot_skill value when autoskill enabled (making bot weaker)
+ if (autoskill && bot_skill < 10) {
+ bot_skill++;
+ }
+
+ if (Game.iDeathsBroadcasting != BROADCAST_DEATHS_NONE) {
+ // This is a human, we will tell this human he has been killed
+ // by a bot.
+ const int r = RANDOM_LONG(150, 255);
+ const int g = RANDOM_LONG(30, 155);
+ const int b = RANDOM_LONG(30, 155);
+ char msg[128];
+ if (Game.iDeathsBroadcasting == BROADCAST_DEATHS_FULL) {
+ snprintf(msg, sizeof(msg), "A RealBot has killed you!\n\nName:%s\nSkill:%d\n", name, bot_skill);
+ } else {
+ snprintf(msg, sizeof(msg), "A RealBot named %s has killed you!", name);
+ }
+
+ HUD_DrawString(r, g, b, msg, pEnemyEdict);
+ }
+ }
+
+ // clear the pointer for this and other bots that might have the same pEnemyEdict
+ FUNC_ClearEnemyPointer(pEnemyEdict);
+
+ // from here react after kill...
+ forgetGoal();
+ forgetPath();
+
+ if (lastSeenEnemyVector != Vector(0, 0, 0)) {
+ vHead = lastSeenEnemyVector;
+ }
+
+ lastSeenEnemyVector = Vector(0, 0, 0);
+
+ // random waiting
+ f_wait_time = gpGlobals->time + (1 + RANDOM_FLOAT(0.0f, 0.4f));
+
+ // keep on walking when afraid (perhaps there are more enemies)
+ if (RANDOM_LONG(0, 100) < ipFearRate)
+ f_walk_time = gpGlobals->time + (1 + RANDOM_FLOAT(0.0f, 2.0f));
+
+ InteractWithPlayers(); // check any new enemy here immediately
+
+ return;
+ }
+
+ // ----------- combat
+
+ // STEP 1: Pick best weapon to fight with
+ PickBestWeapon();
+
+ // STEP 2: Decide how to move to make us a harder target
+ FightEnemy();
+
+ // STEP 3: Aim at enemy (skill-based)
+ AimAtEnemy();
+
+ // STEP 4: Fire!
+ FireWeapon();
+}
+
+/******************************************************************************
+ Function purpose: Find cover
+ Note: Using tracelines to get a cover node.
+ ******************************************************************************/
+void cBot::FindCover() {
+ TraceResult tr;
+ const Vector dest = lastSeenEnemyVector;
+ // Vector start = pEdict->v.origin;
+ // Vector end;
+ Vector cover_vect = Vector(9999, 9999, 9999);
+
+ // TraceLines in 2 directions to find which way to go...
+ UTIL_MakeVectors(pEdict->v.v_angle);
+ const Vector v_src = pEdict->v.origin + pEdict->v.view_ofs;
+ Vector v_right = v_src + gpGlobals->v_right * 90;
+ Vector v_left = v_src + gpGlobals->v_right * -90;
+
+ // We have now our first 'left' and 'right'
+
+ // First check the right..
+ UTIL_TraceLine(v_src, v_right, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
+
+ if (tr.flFraction >= 1.0f) {
+ // We can see it
+ // Now trace from that vector to our threat
+ UTIL_TraceLine(v_right, dest, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
+
+ // If this is blocking.. then its a good wpt
+ if (tr.flFraction < 1.0f)
+ cover_vect = v_right;
+ }
+
+ // Now check at the left
+ UTIL_TraceLine(v_src, v_left, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
+
+ if (tr.flFraction >= 1.0f) {
+ // We can see it
+ // Now trace from that vector to our threat
+ UTIL_TraceLine(v_left, dest, dont_ignore_monsters, pEdict->v.pContainingEntity, &tr);
+
+ // If this is blocking.. then its a good wpt
+ if (tr.flFraction < 1.0f) {
+ // If we already found a wpt, then randomly pick this one
+ if (cover_vect != Vector(9999, 9999, 9999)) {
+ if (RANDOM_LONG(0, 100) < 50)
+ cover_vect = v_left;
+ } else
+ cover_vect = v_left;
+ }
+ }
+ // Now update the V_left and V_right and do the checks again.
+ // Vector old_right = v_right;
+ // Vector old_left = v_left;
+ v_right = v_src + gpGlobals->v_right * 180;
+ v_left = v_src + gpGlobals->v_right * -180;
+
+ // Now check at the right again
+ UTIL_TraceLine(v_src, v_right, dont_ignore_monsters,
+ pEdict->v.pContainingEntity, &tr);
+
+ if (tr.flFraction >= 1.0f) {
+ // We can see it
+ // Now trace from that vector to our threat
+ UTIL_TraceLine(v_right, dest, dont_ignore_monsters,
+ pEdict->v.pContainingEntity, &tr);
+
+ // If this is blocking.. then its a good wpt
+ if (tr.flFraction < 1.0f) {
+ // If we already found a wpt, then randomly pick this one
+ if (cover_vect != Vector(9999, 9999, 9999)) {
+ if (RANDOM_LONG(0, 100) < 50)
+ cover_vect = v_right;
+ } else
+ cover_vect = v_right;
+ }
+ }
+
+ // Now check at the left
+ UTIL_TraceLine(v_src, v_left, dont_ignore_monsters,
+ pEdict->v.pContainingEntity, &tr);
+ if (tr.flFraction >= 1.0f) {
+ // We can see it
+ // Now trace from that vector to our threat
+ UTIL_TraceLine(v_left, dest, dont_ignore_monsters,
+ pEdict->v.pContainingEntity, &tr);
+
+ // If this is blocking.. then its a good wpt
+ if (tr.flFraction < 1.0f) {
+ // If we already found a wpt, then randomly pick this one
+ if (cover_vect != Vector(9999, 9999, 9999)) {
+ if (RANDOM_LONG(0, 100) < 50)
+ cover_vect = v_left;
+ } else
+ cover_vect = v_left;
+ }
+ }
+
+ const int iNodeEnemy = NodeMachine.getClosestNode(pEnemyEdict->v.origin, 60, pEnemyEdict);
+ const int iNodeFrom = NodeMachine.getClosestNode(pEdict->v.origin, NODE_ZONE, pEdict);
+
+ // --------------
+ // TEST TEST TEST
+ // --------------
+ const int iCoverNode = NodeMachine.node_cover(iNodeFrom, iNodeEnemy, pEdict);
+ bool bTakenCover = false;
+
+ if (iCoverNode > -1) {
+ rprint("FindCover()", "cover node found (node based)");
+ setGoalNode(iCoverNode);
+ forgetPath();
+
+ // Calculate a path to this position and get the heck there.
+ createPath(iCoverNode);
+ f_cover_time = gpGlobals->time + 8.0f;
+ bTakenCover = true;
+ } else {
+
+ // --------------------------------------------------
+ // If cover_vect is found, we find a node close to it
+ // --------------------------------------------------
+ if (cover_vect != Vector(9999, 9999, 9999)) {
+ rprint("FindCover()", "cover node found (cover_vect based)");
+ const int iNodeCover = NodeMachine.getClosestNode(cover_vect, 60, pEdict);
+ if (iNodeCover > -1) {
+ setGoalNode(iNodeCover);
+ forgetPath();
+
+ // Calculate a path to this position and get the heck there.
+ rprint("createPath -> find cover node");
+ NodeMachine.createPath(iNodeFrom, iNodeCover, iBotIndex, this, PATH_NONE);
+ f_cover_time = gpGlobals->time + 8;
+ bTakenCover = true;
+ }
+ }
+ }
+
+ // when we have taken cover, and we are leader, command our team to get
+ // into our position to cover area
+ if (bTakenCover) {
+ // do something...
+ }
+
+} // FindCover()
+
+void cBot::InteractWithFriends() {
+
+
+ // TODO TODO TODO; make this thing really work
+ //return;
+
+ // We interact with our players in some way
+ //
+ // When a bot is camping, another bot can choose to say 'go go go' for example.
+ //
+ //
+
+ for (int i = 1; i <= gpGlobals->maxClients; i++) {
+
+ edict_t* pPlayer = INDEXENT(i);
+
+ // skip invalid players and skip self (i.e. this bot)
+ if (pPlayer && !pPlayer->free && pPlayer != pEdict) {
+ // skip this player if not alive (i.e. dead or dying)
+ if (!IsAlive(pPlayer))
+ continue;
+
+ // skip enemies
+ if (UTIL_GetTeam(pPlayer) != UTIL_GetTeam(pEdict))
+ continue;
+
+ bool bCanSeePlayer = false;
+ bool bClose = false;
+
+ Vector vVecEnd = pPlayer->v.origin + pPlayer->v.view_ofs;
+
+ if (func_distance(pPlayer->v.origin, pEdict->v.origin) < 450)
+ bClose = true;
+
+ if (FInViewCone(&vVecEnd, pEdict) && FVisible(vVecEnd, pEdict))
+ bCanSeePlayer = true;
+
+ // there are tons of cases
+ const cBot* pBotPointer = UTIL_GetBotPointer(pPlayer);
+
+ // It is a fellow bot
+ if (pBotPointer != nullptr) {
+ if (bClose) {
+ if (pBotPointer->f_camp_time > gpGlobals->time
+ && pBotPointer->f_camp_time - 10 < gpGlobals->time
+ && pBotPointer->pEnemyEdict == nullptr
+ && (RANDOM_LONG(0, 100) < ipCampRate
+ && FUNC_DoRadio(this))) {
+ // issue go go go
+ UTIL_BotRadioMessage(this, 2, "1", ""); // go go go!
+ }
+ }
+
+ if (bCanSeePlayer) {}
+ } else // it is a teammate, but it is human (or a different bot)
+ {
+ // when firing
+
+ }
+
+ // any player:
+ if (bClose) {
+ // some one is close, need backup?
+ if (RANDOM_LONG(0, 100) < ipFearRate && pEnemyEdict != nullptr)
+ if (FUNC_DoRadio(this)) {
+ UTIL_BotRadioMessage(this, 3, "3", ""); // need backup
+ }
+ }
+ }
+ }
+
+}
+
+// BOT: Interact with Players ('find enemy, and how to react upon them')
+void cBot::InteractWithPlayers() {
+
+ // friends are important, we are a team dudes!
+ InteractWithFriends();
+
+ const int result = FindEnemy();
+
+ // -------------------------------
+ // RESULT < 0; NO ENEMY FOUND
+ // -------------------------------
+
+ // No enemy found, unzoom
+ if (result < 0) {
+ // Keep f_prim_weapon updated, else we do burst immidiatly
+ if (CarryWeaponType() == SNIPER) {
+
+ // Unzoom (for sniper guns)
+ if (zoomed > ZOOM_NONE && f_allow_keypress < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK2);
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ zoomed++;
+ }
+ if (zoomed > ZOOM_TWICE)
+ zoomed = ZOOM_NONE;
+ } else if (FUNC_BotHoldsZoomWeapon(this)) {
+
+ // Unzoom (for other guns with only 1 zoom)
+ if (zoomed > ZOOM_NONE && f_allow_keypress < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK2);
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ zoomed = ZOOM_NONE;
+ }
+ } else {
+
+ // For any weapon that has a silencer (the colt for example), use it if we want that.
+ if (isHoldingWeapon(CS_WEAPON_M4A1))
+ if (bot_use_special == 0 && zoomed == ZOOM_NONE
+ && f_allow_keypress < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK2);
+ zoomed = ZOOM_ONCE;
+ }
+ }
+ }
+ // ------------------------------------------------
+ // RESULT > -1 ; ENEMY FOUND / NO SPECIFIC REACTION
+ // ------------------------------------------------
+ else { // result > -1
+
+ // VIP: When we found an enemy, we have a problem.
+ if (vip) {
+
+ // We do not forget our enemy, but we will try to get the heck out of here.
+ // A VIP bot should prioritize survival. Upon spotting an enemy, it should
+ // immediately seek cover and call for backup. This increases the chances of
+ // the VIP surviving the encounter.
+ FindCover(); // Find a suitable cover position away from the enemy.
+ if (FUNC_DoRadio(this)) {
+ UTIL_BotRadioMessage(this, 3, "3", ""); // Radio for backup.
+ }
+
+ }
+ // Whenever we hold a knife, get our primary weapon
+ if (CarryWeapon(CS_WEAPON_KNIFE)) {
+
+ // switch back to primary
+ if (iPrimaryWeapon > -1)
+ UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iPrimaryWeapon));
+
+ else // pick secondary
+ UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(iSecondaryWeapon));
+
+ f_update_weapon_time = gpGlobals->time + 0.7f;
+ }
+ }
+
+ // ------------------------------------------------
+ // RESULT = 0 ; NEW ENEMY FOUND
+ // ------------------------------------------------
+ if (result == 0) {
+ // First Encounter
+ //f_prim_weapon = gpGlobals->time;
+ if (CarryWeaponType() == SNIPER) {
+ if (zoomed < ZOOM_TWICE && f_allow_keypress < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK2);
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ zoomed++;
+ }
+ }
+
+ // INITIALIZATION:
+ const int iGoal = NodeMachine.getClosestNode(pEnemyEdict->v.origin, NODE_ZONE, pEnemyEdict);
+ if (iGoal > -1) {
+ rprint_trace("InteractWithPlayers()", "Found a new enemy, setting goal and forgetting path");
+ setGoalNode(iGoal);
+ forgetPath();
+ }
+
+ // Speed our enemy runs
+ // int run_speed = FUNC_PlayerSpeed(pBot->pBotEnemy);
+ // Distance between Us and Enemy.
+ // float f_distance = func_distance(pBot->pEdict->v.origin,
+ // pBot->pBotEnemy->v.origin);
+
+ // Does our enemy (when a bot) has focus on us?
+ bool focused;
+ const cBot* playerbot = UTIL_GetBotPointer(pEnemyEdict);
+ if (playerbot) {
+ if (playerbot->pEnemyEdict == pEdict)
+ focused = true;
+ }
+ else // Its a human
+ {
+
+ // When we are in his 'sight' of 25 degrees , we are pretty
+ // much focussed for a first encounter.
+ if (FUNC_InFieldOfView
+ (pEdict, (pEnemyEdict->v.origin - pEdict->v.origin)) < 25)
+ focused = true;
+ }
+
+ /******************************
+ At this moment we know:
+ - The distance between us and enemy
+ - The focus (are we targetted too?)
+ - The speed of the enemy (running, standing still? etc)
+ *******************************/
+ } // We have a first encounter
+
+ // ------------------------------------------------
+ // RESULT = 3 ; NEWER ENEMY FOUND
+ // ------------------------------------------------
+ if (result == 3) {
+ //
+ // Newer enemy found, update goals and such, but thats all!
+ //
+
+ // INITIALIZATION:
+ const int iGoal = NodeMachine.getClosestNode(pEnemyEdict->v.origin, NODE_ZONE, pEnemyEdict);
+
+ if (iGoal > -1) {
+ rprint_trace("InteractWithPlayers()", "Found a *newer* enemy, so picking goal node to that");
+ setGoalNode(iGoal);
+ forgetPath();
+ }
+ }
+}
+
+// BOT: INTERACT WITH PLAYERS
+void cBot::JoinTeam() {
+ if (mod_id != CSTRIKE_DLL) return;
+ // When bot plays Counter-Strike (only Counter-Strike is supported)
+
+ char c_class[32];
+
+ // Choose team first
+ if (start_action == MSG_CS_TEAM_SELECT) {
+ char c_team[32];
+ start_action = MSG_CS_IDLE; // switch back to idle
+
+ // in case of bad state/input fall-back to 'pick one for me'
+ if (iTeam != 1 && iTeam != 2 && iTeam != 5) {
+ iTeam = 5;
+ }
+
+ // select the team the bot wishes to join...
+ if (iTeam == 1) {
+ std::strcpy(c_team, "1");
+ }
+ else if (iTeam == 2) {
+ std::strcpy(c_team, "2");
+ }
+ else {
+ std::strcpy(c_team, "5");
+ }
+
+ // choose
+ FakeClientCommand(this->pEdict, "menuselect", c_team, nullptr);
+
+ return;
+ }
+
+ // counter terrorist menu, which class/outfit?
+ if (start_action == MSG_CS_CT_SELECT) {
+ start_action = MSG_CS_IDLE; // switch back to idle
+
+ if (bot_class < 1 || bot_class > 4)
+ bot_class = 5; // use random if invalid
+
+ // Since cs 1.6 does not give us pretty random models
+ // we do it ourselves
+ if (bot_class == 5) {
+ bot_class = RANDOM_LONG(1, 4);
+ }
+
+ // select the class the bot wishes to use...
+ if (bot_class == 1)
+ std::strcpy(c_class, "1");
+ else if (bot_class == 2)
+ std::strcpy(c_class, "2");
+ else if (bot_class == 3)
+ std::strcpy(c_class, "3");
+ else if (bot_class == 4)
+ std::strcpy(c_class, "4");
+ else
+ std::strcpy(c_class, "5"); // random
+
+ FakeClientCommand(this->pEdict, "menuselect", c_class, nullptr);
+
+ // bot has now joined a team
+ hasJoinedTeam = true;
+
+ return;
+ }
+
+ // terrorist select
+ if (start_action == MSG_CS_T_SELECT) {
+ start_action = MSG_CS_IDLE; // switch back to idle
+
+ if (bot_class < 1 || bot_class > 4)
+ bot_class = 5; // use random if invalid
+
+ // Since cs 1.6 does not give us pretty random models
+ // we do it ourselves
+ if (bot_class == 5) {
+ bot_class = RANDOM_LONG(1, 4);
+ }
+
+ // select the class the bot wishes to use...
+ if (bot_class == 1)
+ std::strcpy(c_class, "1");
+ else if (bot_class == 2)
+ std::strcpy(c_class, "2");
+ else if (bot_class == 3)
+ std::strcpy(c_class, "3");
+ else if (bot_class == 4)
+ std::strcpy(c_class, "4");
+ else
+ std::strcpy(c_class, "5"); // random
+
+ FakeClientCommand(this->pEdict, "menuselect", c_class, nullptr);
+
+ // bot has now joined the game (doesn't need to be started)
+ hasJoinedTeam = true;
+
+ //return;
+ }
+}
+
+vec_t cBot::ReturnTurnedAngle(float speed, float current, const float ideal) {
+
+ // hope this fix the unnescesary turning of bots.
+ // how? we save the values here, andc alculate the new value.
+ // this part is copied from botchangeyaw/pitch so it SHOULD work :)
+ float current_180; // current +/- 180 degrees
+
+ // turn from the current v_angle pitch to the idealpitch by selecting
+ // the quickest way to turn to face that direction
+
+ // find the difference in the current and ideal angle
+ const float diff = std::fabs(current - ideal);
+
+ // check if the bot is already facing the idealpitch direction...
+ if (diff <= 1.0f)
+ return current; // return number of degrees turned
+
+ // check if difference is less than the max degrees per turn
+ speed = std::min(diff, speed); // just need to turn a little bit (less than max)
+
+ // here we have four cases, both angle positive, one positive and
+ // the other negative, one negative and the other positive, or
+ // both negative. handle each case separately...
+ if (current >= 0.0f && ideal >= 0.0f) // both positive
+ {
+ if (current > ideal)
+ current -= speed;
+
+ else
+ current += speed;
+ } else if (current >= 0.0f && ideal < 0.0f) {
+ current_180 = current - 180.0f;
+ if (current_180 > ideal)
+ current += speed;
+
+ else
+ current -= speed;
+ } else if (current < 0 && ideal >= 0) {
+ current_180 = current + 180;
+ if (current_180 > ideal)
+ current += speed;
+
+ else
+ current -= speed;
+ } else // (current < 0) && (ideal < 0) both negative
+ {
+ if (current > ideal)
+ current -= speed;
+
+ else
+ current += speed;
+ }
+
+ // check for wrap around of angle...
+ if (current > 180)
+ current -= 360;
+ if (current < -180)
+ current += 360;
+ return current; // return what it should be
+}
+
+// BOT: sub-function (DEFUSE) for ACT()
+bool cBot::Defuse() {
+ if (!isCounterTerrorist()) // non-Counter-Terrorists have no business here
+ return false;
+
+ // this bot is defusing
+ if (shouldActWithC4() && keyPressed(IN_USE)) {
+ setTimeToMoveToNode(3);
+ return true;
+ }
+
+ // What i do, i search for the c4 timer, store its origin and check
+ // if this bot is close. If so, the bot should be defusing the bomb
+ // if the timers are set. The above check makes sure that no other
+ // bot will be defusing the bomb.
+ edict_t* pent = nullptr;
+ while ((pent = UTIL_FindEntityByClassname(pent, "grenade")) != nullptr) {
+ if (UTIL_GetGrenadeType(pent) == 4) { // It is a C4
+ break;
+ }
+ }
+
+ if (pent == nullptr) {
+ rprint_normal("Defuse()", "No C4 planted yet");
+ return false;
+ }
+
+ rprint_normal("Defuse()", "C4 is planted!");
+
+ // A c4 has been found, oh dear.
+ // Remember, pent=c4 now!
+
+ // Calculate the distance between our position to the c4
+ assert(pent != nullptr);
+ const Vector vC4 = pent->v.origin;
+
+ const float distance = func_distance(pEdict->v.origin, vC4);
+
+ // can see C4
+ const bool canSeeC4 = canSeeVector(vC4, pent);
+
+ if (!canSeeC4) {
+ rprint_trace("Defuse()", "Cannot see planted C4 - bailing");
+ return false;
+ }
+
+ // it can be seen, so it has been discovered
+ if (!Game.isPlantedC4Discovered()) {
+ this->rprint_trace("Defuse()", "C4 is discovered, remembering its coordinates");
+ Game.vPlantedC4 = vC4;
+ }
+
+ // We can do 2 things now
+ // - If we are not close, we check if we can walk to it, and if so we face to the c4
+ // - If we are close, we face it and (begin) defuse the bomb.
+ constexpr int distanceForC4ToBeInReach = 70;
+ if (distance < distanceForC4ToBeInReach) {
+ vHead = vC4;
+ vBody = vC4;
+
+ setTimeToMoveToNode(3); // we are going to do non-path-follow stuff, so keep timer updated
+ const int angle_to_c4 = FUNC_InFieldOfView(pEdict, (vC4 - pEdict->v.origin));
+
+ // if defusion timer has not been set (ie, the bot is not yet going to defuse the bomb)
+ if (f_defuse < gpGlobals->time && angle_to_c4 < 35) {
+ this->rprint("Defuse()", "I'll start defusing the bomb");
+ // when we are 'about to' defuse, we simply set the timers
+ f_defuse = gpGlobals->time + 90; // hold as long as you can
+ f_allow_keypress = gpGlobals->time + 1.5f; // And stop any key pressing the first second
+ // ABOUT TO DEFUSE BOMB
+ }
+
+ // Defusion timer is set and c4 is within vision
+ if (f_defuse > gpGlobals->time && angle_to_c4 < 35) {
+ this->rprint("Defuse()", "I'm defusing the bomb");
+ setMoveSpeed(0.0);
+ f_c4_time = gpGlobals->time + 6;
+ UTIL_BotPressKey(this, IN_DUCK);
+
+ if (func_distance(pEdict->v.origin, vC4) > 50
+ && f_allow_keypress + 0.5f > gpGlobals->time) {
+ setMoveSpeed(f_max_speed / 2);
+ }
+ }
+
+ if (f_allow_keypress < gpGlobals->time && f_defuse > gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_USE);
+ }
+
+ } else {
+ rprint_trace("Defuse()", "I can see C4, but it is out of reach.");
+ const int iC4Node = NodeMachine.getClosestNode(vC4, distanceForC4ToBeInReach, nullptr);
+ if (iC4Node < 0) {
+ rprint_normal("Defuse()", "No node close, so just look at it/body face at it and move towards it.");
+ vHead = vC4;
+ vBody = vC4;
+ }
+
+ if (iC4Node > -1) {
+ // we are not heading for this goal yet
+ if (getGoalNode() != iC4Node) {
+ rprint_normal("Defuse()", "I don't have a goal towards the C4, overriding it now to C4 destination!");
+ forgetPath();
+ forgetGoal();
+ setGoalNode(iC4Node);
+ } else {
+ rprint_normal("Defuse()", "I already have a goal towards the C4!");
+ }
+ } else {
+ rprint_normal("Defuse()", "C4 is somewhere without a close node.");
+ }
+ setMoveSpeed(f_max_speed);
+ } // distance < ...
+
+ // we can see the bomb, and we act upon it
+ return true;
+}
+
+int cBot::keyPressed(const int key) const {
+ return pEdict->v.button & key;
+}
+
+// BOT: Act
+void cBot::Act() {
+ // chat
+ if (fChatTime < gpGlobals->time) {
+ if (chChatSentence[0] != '\0') {
+ UTIL_SayTextBot(chChatSentence, this);
+ std::memset(chChatSentence, 0, sizeof(chChatSentence));
+ }
+ }
+
+ // camp
+ if (f_camp_time > gpGlobals->time) {
+ // When camping we duck and we don't move
+ UTIL_BotPressKey(this, IN_DUCK);
+
+
+ setMoveSpeed(0.0f); // do not move
+ PickBestWeapon(); // pick weapon, do not stare with knife
+
+ // when dropped C4 and CT we look at C4
+ if (isCounterTerrorist() && Game.vDroppedC4 != Vector(9999, 9999, 9999)) {
+ // look at dropped C4
+ if (EntityIsVisible(pEdict, Game.vDroppedC4))
+ vHead = Game.vDroppedC4;
+ else {
+ if (iGoalNode > -1)
+ {
+ forgetPath();
+ forgetGoal();
+ vHead = vBody = NodeMachine.node_vector(iGoalNode);
+ }
+ else {
+ vHead = vBody = Game.vDroppedC4;
+ }
+ }
+ }
+ else {
+ // Look at iGoalNode
+ if (iGoalNode > -1)
+ {
+ forgetPath();
+ forgetGoal();
+ vHead = vBody = NodeMachine.node_vector(iGoalNode);
+ }
+ else {
+ vHead = vBody = pEdict->v.origin;
+ }
+ }
+ }
+
+ // C4 timer is set, this means:
+ // T -> Is planting bomb
+ // CT-> Is defusing bomb
+ if (shouldActWithC4()) {
+ // make sure we override this, or else we learn that we get stuck or something
+ // which is not the case.
+ setTimeToMoveToNode(2);
+
+ // terrorist
+ if (isTerrorist()) {
+ // When still having the C4
+ setMoveSpeed(0.0f);
+ // f_strafe_speed = 0.0f;
+
+ // When no C4 selected yet, select it
+ if (!isHoldingWeapon(CS_WEAPON_C4)) {
+ UTIL_SelectItem(pEdict, "weapon_c4");
+ }
+ else {
+ UTIL_BotPressKey(this, IN_ATTACK); // plant it!
+ }
+
+ // When we no longer have the C4 , we stop doing this stupid shit
+ if (!hasBomb() || Game.bBombPlanted) {
+ rprint_trace("Act()", "I was planting the C4, and it got planted (I no longer have the C4), so find a nearby node to camp/guard the C4");
+ f_c4_time = gpGlobals->time;
+ setGoalNode(NodeMachine.getClosestNode(pEdict->v.origin, 200, pEdict));
+ iPathFlags = PATH_CAMP;
+ forgetPath();
+ }
+ }
+ else {
+ // counter-terrorist
+ Defuse(); // old routine from RB AI V1.0 defusing, should get here and more cleaned up
+ }
+ }
+
+ if (f_strafe_time < gpGlobals->time) {
+ f_strafe_speed = 0.0f;
+ }
+
+ // walk only when NOT holding duck (is same as walking, combination makes bot super slow)
+ if (f_walk_time > gpGlobals->time && !(pEdict->v.button & IN_DUCK)) {
+ // From "KickBot": return (float) (((int)flMaxSpeed)/2 + ((int)flMaxSpeed)/50);
+ //OLD: f_move_speed = f_max_speed / 2.0; // this is not correct
+
+ pEdict->v.button &= ~IN_RUN; // release IN_RUN
+ rprint("Act", "Walk time > gpGlobals->time");
+ setMoveSpeed(f_max_speed / 2.0f + f_max_speed / 50.0f);
+ }
+
+ // When we are at max speed, press IN_RUN to get a running animation
+ if (f_move_speed == f_max_speed) {
+ UTIL_BotPressKey(this, IN_RUN);
+ }
+
+ if (!keyPressed(IN_MOVELEFT) || keyPressed(IN_MOVERIGHT)) {
+ if (f_strafe_speed > 0.0f) {
+ UTIL_BotPressKey(this, IN_MOVERIGHT);
+ }
+ else if (f_strafe_speed < 0.0f) {
+ UTIL_BotPressKey(this, IN_MOVELEFT);
+ }
+ }
+
+ // When we should go back, we go back
+ if (f_goback_time > gpGlobals->time) {
+ setMoveSpeed(-f_max_speed);
+ }
+
+ // When holding duck, we hold duck
+ if (f_hold_duck > gpGlobals->time)
+ UTIL_BotPressKey(this, IN_DUCK);
+
+ // When we wait, we have no move speed
+ // notice: 'wait' is not 'stuck' nor 'camping'. Wait should only be used to have a bot
+ // 'do nothing' for a short period of time.
+ if (f_wait_time > gpGlobals->time) {
+ rprint("Act", "f_wait_time > gpGlobals->time");
+ setMoveSpeed(0.0f);
+ }
+
+ // Button usage, change vBody to a 'trigger multiple' because we have to touch these
+ if (pButtonEdict) {
+ if (std::strcmp(STRING(pButtonEdict->v.classname), "trigger_multiple") == 0) {
+ if (func_distance(pEdict->v.origin, VecBModelOrigin(pButtonEdict)) < 60) {
+ vBody = VecBModelOrigin(pButtonEdict);
+ }
+ }
+ }
+
+ // -------------------------------------------
+ // MOVE TO : vBody
+ // calculate the angle we MOVE to. (VecMoveAngles)
+ // -------------------------------------------
+ Vector vTarget = vBody - pEdict->v.origin;
+ vecMoveAngles = UTIL_VecToAngles(vTarget);
+
+ // Paulo-La-Frite - START bot aiming bug fix
+ if (vecMoveAngles.x > 180)
+ vecMoveAngles.x -= 360;
+
+ vecMoveAngles.x = -vecMoveAngles.x;
+ vecMoveAngles.z = 0;
+ UTIL_FixAngles(&vecMoveAngles);
+
+ // when filled in, we look to this (overrides)
+ if (vEar != Vector(9999, 9999, 9999))
+ vHead = vEar;
+
+ // button overrides hearing
+ if (pButtonEdict)
+ vHead = VecBModelOrigin(pButtonEdict);
+
+ // -------------------------------------------
+ // FACE AT: vHead
+ // calculate the angle we face at.
+ //
+ // -------------------------------------------
+ vTarget = vHead - pEdict->v.origin;
+ pEdict->v.v_angle = UTIL_VecToAngles(vTarget);
+ if (pEdict->v.v_angle.y > 180.0f)
+ pEdict->v.v_angle.y -= 360.0f;
+
+ // Paulo-La-Frite - START bot aiming bug fix
+ if (pEdict->v.v_angle.x > 180.0f)
+ pEdict->v.v_angle.x -= 360.0f;
+
+ Vector v_shouldbe;
+
+ // Vector how it should be, however, we don't allow such a fast turn!
+ v_shouldbe.x = pEdict->v.v_angle.x / 3;
+ v_shouldbe.y = pEdict->v.v_angle.y;
+ v_shouldbe.z = 0; //unused? [APG]RoboCop[CL]
+
+ // set the body angles to point the gun correctly
+ pEdict->v.angles.x = ReturnTurnedAngle(static_cast(ipTurnSpeed), pEdict->v.angles.x, v_shouldbe.x);
+ pEdict->v.angles.y = ReturnTurnedAngle(static_cast(ipTurnSpeed), pEdict->v.angles.y, v_shouldbe.y);
+ pEdict->v.angles.z = 0;
+
+ // adjust the view angle pitch to aim correctly (MUST be after body v.angles stuff)
+ pEdict->v.v_angle.x = -pEdict->v.v_angle.x;
+
+ // Paulo-La-Frite - END
+ pEdict->v.ideal_yaw = pEdict->v.v_angle.y;
+ pEdict->v.idealpitch = pEdict->v.v_angle.x;
+
+ botFixIdealYaw(pEdict);
+ botFixIdealPitch(pEdict);
+}
+
+bool cBot::shouldActWithC4() const
+{
+ return f_c4_time > gpGlobals->time;
+}
+
+// BOT: On ladder?
+bool cBot::isOnLadder() const
+{
+ return FUNC_IsOnLadder(pEdict);
+}
+
+// BOT: Check around body and avoid obstacles
+void cBot::CheckAround() {
+ rprint_trace("CheckAround", "Start");
+ // Do not act when on ladder
+ if (isOnLadder())
+ return;
+
+ // The principle is to fire 2 tracelines, both forward; one left
+ // and one right. When one of the 2 gets hit, we know we are 'about'
+ // to get hit. Therefor we use strafing to keep distance to the coming wall
+ // when left and right is both hit we have a problem as this should not happen.
+
+ // Note: we use TRACEHULL instead of TRACELINE, because TRACEHULL detects
+ // the famous 'undetectable' func_walls.
+ TraceResult tr;
+
+ // v_source = pEdict->v.origin + Vector(0, 0, -CROUCHED_HEIGHT + (MAX_JUMPHEIGHT + 1));
+ const Vector v_source = pEdict->v.origin + Vector(0, 0, ORIGIN_HEIGHT);
+
+ // Go forward first
+ constexpr float distance = 90.0f;
+ const Vector v_forward = v_source + gpGlobals->v_forward * distance;
+
+ // now really go left/right
+ const Vector v_right = v_source + gpGlobals->v_right * distance;
+ const Vector v_left = v_source + gpGlobals->v_right * -distance;
+
+ // now really go left/right
+ const Vector v_forwardright = v_right + gpGlobals->v_forward * distance;
+ const Vector v_forwardleft = v_left + gpGlobals->v_forward * -distance;
+
+ // TRACELINE: forward
+ UTIL_TraceHull(v_source, v_forward, dont_ignore_monsters, point_hull, pEdict, &tr);
+ const bool bHitForward = tr.flFraction < 1.0f;
+
+ // TRACELINE: Left
+ UTIL_TraceHull(v_source, v_left, dont_ignore_monsters, point_hull, pEdict, &tr);
+ const bool bHitLeft = tr.flFraction < 1.0f;
+
+ // TRACELINE: Right
+ UTIL_TraceHull(v_source, v_right, dont_ignore_monsters, point_hull, pEdict, &tr);
+ const bool bHitRight = tr.flFraction < 1.0f;
+
+ // TRACELINE: Forward left
+ UTIL_TraceHull(v_source, v_forwardleft, dont_ignore_monsters, point_hull, pEdict, &tr);
+ const bool bHitForwardLeft = tr.flFraction < 1.0f;
+
+ // TRACELINE: Forward right
+ UTIL_TraceHull(v_source, v_forwardright, dont_ignore_monsters, point_hull, pEdict, &tr);
+ const bool bHitForwardRight = tr.flFraction < 1.0f;
+
+ char msg[255];
+ snprintf(msg, sizeof(msg), "HIT results: forward: %d, left: %d, right: %d, forward left: %d, forward right: %d", bHitForward, bHitLeft, bHitRight, bHitForwardLeft, bHitForwardRight);
+ rprint_trace("CheckAround", msg);
+
+ // Set 'act' properties
+ const float strafeAmount = DetermineStrafe(bHitForwardLeft, bHitForwardRight, bHitLeft, bHitRight);
+ if (strafeAmount != 0.0f) {
+ setStrafeSpeed(strafeAmount, 0.5f);
+ }
+
+ // we are surrounded, so move backwards, but only if we are not strafing
+ if (bHitForward && strafeAmount == 0.0f) {
+ rprint_trace("CheckAround", "Something in front of me blocks, so move back.");
+ setMoveSpeed(-f_max_speed);
+ }
+ else {
+ rprint_trace("CheckAround", "Nothing in front of me");
+ }
+}
+
+// BOT: Should be taking cover?
+bool cBot::TakeCover() const
+{
+ // Its time based.
+ if (f_cover_time < gpGlobals->time)
+ return false;
+
+ // And if all went fine, we can return true.
+ return true;
+}
+
+/**
+ * Set the node to follow next as the next one (ie, increase index)
+ */
+void cBot::nextPathIndex()
+{
+ this->pathIndex++;
+}
+
+/**
+ * Set the node to follow next as the previous one (ie, decrease index). Calls forgetPath when index is getting < 0
+ */
+void cBot::prevPathIndex()
+{
+ rprint("prevPathNodeIndex");
+ this->pathIndex--;
+ if (this->pathIndex < 0) {
+ forgetPath();
+ }
+}
+
+// Returns true if bot has a path to follow
+bool cBot::isWalkingPath() const
+{
+ return this->pathIndex > -1;
+}
+
+// Returns true if bot has goal node
+bool cBot::hasGoal() const
+{
+ return this->iGoalNode > -1;
+}
+
+// Returns true if bot has goal node index (ie referring to Goals[])
+bool cBot::hasGoalIndex() const
+{
+ return this->goalIndex > -1;
+}
+
+/**
+ * Returns goal data , if goal data exists
+ * @return
+ */
+tGoal* cBot::getGoalData() const
+{
+ if (!hasGoalIndex()) return nullptr;
+ tGoal* ptr = NodeMachine.getGoal(this->goalIndex);
+ if (ptr == nullptr) return nullptr;
+
+ // only goals with a node are valid
+ if (ptr->iNode > -1) return ptr;
+ // else not
+
+ return nullptr;
+}
+
+// Returns true if bot has an enemy edict
+bool cBot::hasEnemy() const
+{
+ return this->pEnemyEdict != nullptr;
+}
+
+/**
+ * Returns true when given edict == our enemy edict
+ * @param pEntity
+ * @return
+ */
+bool cBot::hasEnemy(const edict_t* pEntity) const
+{
+ return this->pEnemyEdict == pEntity;
+}
+
+// Returns true if bot has a path to follow
+bool cBot::shouldBeWandering() {
+ if (this->fWanderTime > gpGlobals->time) {
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "Wander time is %f , globals time is %f, so should still wander", this->fWanderTime, gpGlobals->time);
+ rprint(msg);
+ return true;
+ }
+ return false;
+}
+
+void cBot::setMoveSpeed(const float value) {
+ // char msg[255];
+ // sprintf(msg, "setting to value %f / maxSpeed %f - sv_maxspeed = %f", value, this->f_max_speed, CVAR_GET_FLOAT("sv_maxspeed"));
+ // rprint_trace("setMoveSpeed", msg);
+ this->f_move_speed = value;
+}
+
+void cBot::setStrafeSpeed(const float value, const float time) {
+ char msg[255];
+ snprintf(msg, sizeof(msg), "%f for %f seconds.", value, time);
+ rprint_trace("setStrafeSpeed", msg);
+ // if (f_strafe_time > gpGlobals->time) {
+ //
+ // } else {
+ f_strafe_speed = value;
+ f_strafe_time = gpGlobals->time + time;
+ // }
+}
+
+void cBot::strafeLeft(const float time)
+{
+ setStrafeSpeed(-f_max_speed, time);
+}
+
+void cBot::strafeRight(const float time)
+{
+ setStrafeSpeed(f_max_speed, time);
+}
+
+void cBot::startWandering(const float time)
+{
+ this->fWanderTime = gpGlobals->time + time;
+ setMoveSpeed(f_max_speed);
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "Start wandering for %f seconds", time);
+ rprint("startWandering", msg);
+}
+
+void cBot::stopMoving()
+{
+ this->setMoveSpeed(0.0f);
+}
+
+void cBot::forgetGoal()
+{
+ rprint_trace("forgetGoal");
+ this->iGoalNode = -1;
+ this->goalIndex = -1;
+}
+
+int cBot::getPathIndex() const
+{
+ return this->pathIndex;
+}
+
+int cBot::getPreviousPathIndex() const
+{
+ return this->pathIndex - 1;
+}
+
+void cBot::forgetPath()
+{
+ rprint("forgetPath");
+ this->pathIndex = -1;
+ NodeMachine.path_clear(this->iBotIndex);
+}
+
+void cBot::forgetEnemy() {
+ this->pEnemyEdict = nullptr;
+}
+
+edict_t* cBot::getEnemyEdict() const
+{
+ return this->pEnemyEdict;
+}
+
+int cBot::getGoalNode() const
+{
+ return this->iGoalNode;
+}
+
+void cBot::setGoalNode(const int nodeIndex, const int iGoalIndex) {
+ if (nodeIndex < 0) {
+ rprint("setGoalNode()", "WARN: Setting a goal lower than 0, assuming this is not intentional. If you need to forget a goal, use forgetGoal()");
+ }
+ this->iGoalNode = nodeIndex;
+ this->goalIndex = iGoalIndex;
+
+ tGoal* goalPtr = getGoalData();
+ char msg[255] = {};
+
+ if (goalPtr != nullptr) {
+ snprintf(msg, sizeof(msg), "Setting iGoalNode to [%d] and goalIndex [%d] - GOAL: type [%s], checked [%d]",
+ nodeIndex,
+ goalIndex,
+ goalPtr->name,
+ goalPtr->iChecked
+ );
+ } else {
+ snprintf(msg, sizeof(msg), "Setting iGoalNode to [%d] and goalIndex [%d] - could not retrieve goal data.", nodeIndex, goalIndex);
+ }
+ rprint("setGoalNode()", msg);
+}
+
+void cBot::setGoalNode(const int nodeIndex)
+{
+ this->setGoalNode(nodeIndex, -1);
+}
+
+void cBot::setGoalNode(tGoal* goal)
+{
+ if (goal != nullptr && goal->iNode > -1) {
+ rprint("setGoalNode with goal pointer\n");
+ this->setGoalNode(goal->iNode, goal->index);
+ }
+}
+
+/**
+ * Always printed when debug mode is on
+ * @param Function
+ * @param msg
+ */
+void cBot::rprint(const char* Function, const char* msg)
+{
+ REALBOT_PRINT(this, Function, msg);
+}
+
+/**
+ * Only printed when debug mode is on and verbosity is trace
+ * @param Function
+ * @param msg
+ */
+void cBot::rprint_trace(const char* Function, const char* msg)
+{
+ if (Game.messageVerbosity > 2) { // Adjust verbosity level for trace
+ REALBOT_PRINT(this, Function, msg);
+ }
+}
+
+/**
+ * Only printed when debug mode is on and verbosity is normal
+ * @param Function
+ * @param msg
+ */
+void cBot::rprint_normal(const char* Function, const char* msg)
+{
+ if (Game.messageVerbosity > 1) { // Keep verbosity level for normal
+ REALBOT_PRINT(this, Function, msg);
+ }
+}
+
+void cBot::rprint(const char* msg) {
+ rprint("rprint()", msg);
+}
+
+void cBot::rprint_normal(const char* msg) {
+ rprint_normal("rprint()", msg);
+}
+
+void cBot::rprint_trace(const char* msg) {
+ rprint_trace("rprint()", msg);
+}
+
+bool cBot::hasBomb() const
+{
+ return isOwningWeapon(CS_WEAPON_C4);
+}
+
+bool cBot::isCounterTerrorist() const
+{
+ return iTeam == 2;
+}
+
+bool cBot::isTerrorist() const
+{
+ return iTeam == 1;
+}
+
+bool cBot::hasPrimaryWeaponEquiped() const
+{
+ return iPrimaryWeapon > -1;
+}
+
+bool cBot::hasSecondaryWeaponEquiped() const
+{
+ return iSecondaryWeapon > -1;
+}
+
+/*bool cBot::hasPrimaryWeapon(const int weaponId) const
+{
+ return isOwningWeapon(weaponId);
+}
+
+bool cBot::hasSecondaryWeapon(const int weaponId) const
+{
+ return isOwningWeapon(weaponId);
+}*/
+
+void cBot::performBuyWeapon(const char* menuItem, const char* subMenuItem) {
+ // To be sure the console will only change when we MAY change.
+ // The values will only be changed when console_nr is 0
+ if (Game.getRoundStartedTime() + 4 < gpGlobals->time)
+ return; // Not valid to buy
+
+ if (this->console_nr == 0) {
+ // set up first command and argument
+ std::strcpy(this->arg1, "buy");
+ std::strcpy(this->arg2, menuItem);
+
+ if (subMenuItem != nullptr) std::strcpy(this->arg3, subMenuItem);
+
+ this->console_nr = 1; // start console command sequence
+ }
+}
+
+void cBot::performBuyActions(const int weaponIdToBuy) {
+ if (weaponIdToBuy < 0) {
+ return;
+ }
+ // Buy...
+
+ // TODO
+ // FRASHMAN 30.08.04 haven't changed the cs 1.5 buycode, maybe there are also errors
+
+ // CS 1.5 only
+ if (counterstrike == 0) {
+ switch (weaponIdToBuy) {
+ case CS_WEAPON_AK47:
+ performBuyWeapon("4", "1");
+ break;
+ case CS_WEAPON_DEAGLE:
+ performBuyWeapon("1", "3");
+ break;
+ case CS_WEAPON_P228:
+ performBuyWeapon("1", "4");
+ break;
+ case CS_WEAPON_SG552:
+ performBuyWeapon("4", "2");
+ break;
+ case CS_WEAPON_SG550:
+ performBuyWeapon("4", "8");
+ break;
+ case CS_WEAPON_SCOUT:
+ performBuyWeapon("4", "5");
+ break;
+ case CS_WEAPON_AWP:
+ performBuyWeapon("4", "6");
+ break;
+ case CS_WEAPON_MP5NAVY:
+ performBuyWeapon("3", "1");
+ break;
+ case CS_WEAPON_UMP45:
+ performBuyWeapon("3", "5");
+ break;
+ case CS_WEAPON_ELITE:
+ performBuyWeapon("1", "5");
+ break; // T only
+ case CS_WEAPON_MAC10:
+ performBuyWeapon("3", "4");
+ break; // T only
+ case CS_WEAPON_AUG:
+ performBuyWeapon("4", "4");
+ break; // CT Only
+ case CS_WEAPON_FIVESEVEN:
+ performBuyWeapon("1", "6");
+ break; // CT only
+ case CS_WEAPON_M4A1:
+ performBuyWeapon("4", "3");
+ break; // CT Only
+ case CS_WEAPON_TMP:
+ performBuyWeapon("3", "2");
+ break; // CT only
+ case CS_WEAPON_HEGRENADE:
+ performBuyWeapon("8", "4");
+ break;
+ case CS_WEAPON_XM1014:
+ performBuyWeapon("2", "2");
+ break;
+ case CS_WEAPON_SMOKEGRENADE:
+ performBuyWeapon("8", "5");
+ break;
+ case CS_WEAPON_USP:
+ performBuyWeapon("1", "1");
+ break;
+ case CS_WEAPON_GLOCK18:
+ performBuyWeapon("1", "2");
+ break;
+ case CS_WEAPON_M249:
+ performBuyWeapon("5", "1");
+ break;
+ case CS_WEAPON_M3:
+ performBuyWeapon("2", "1");
+ break;
+ case CS_WEAPON_G3SG1:
+ performBuyWeapon("4", "7");
+ break;
+ case CS_WEAPON_FLASHBANG:
+ performBuyWeapon("8", "3");
+ break;
+ case CS_WEAPON_P90:
+ performBuyWeapon("3", "3");
+ break;
+
+ // Armor
+ case CS_WEAPON_ARMOR_LIGHT:
+ performBuyWeapon("8", "1");
+ break;
+ case CS_WEAPON_ARMOR_HEAVY:
+ performBuyWeapon("8", "2");
+ break;
+
+ case CS_DEFUSEKIT:
+ performBuyWeapon("8", "6");
+ break;
+ }
+ }
+
+ // CS 1.6 only
+ else if (counterstrike == 1) { // FRASHMAN 30/08/04: redone switch block, it was full of errors
+ switch (weaponIdToBuy) {
+ //Pistols
+ case CS_WEAPON_GLOCK18:
+ performBuyWeapon("1", "1");
+ break;
+ case CS_WEAPON_USP:
+ performBuyWeapon("1", "2");
+ break;
+ case CS_WEAPON_P228:
+ performBuyWeapon("1", "3");
+ break;
+ case CS_WEAPON_DEAGLE:
+ performBuyWeapon("1", "4");
+ break;
+ case CS_WEAPON_FIVESEVEN:
+ performBuyWeapon("1", "5");
+ break; // CT Only
+ case CS_WEAPON_ELITE:
+ performBuyWeapon("1", "5");
+ break; // T Only
+ //ShotGUNS
+ case CS_WEAPON_M3:
+ performBuyWeapon("2", "1");
+ break;
+ case CS_WEAPON_XM1014:
+ performBuyWeapon("2", "2");
+ break;
+ //SMG
+ case CS_WEAPON_MAC10:
+ performBuyWeapon("3", "1");
+ break; // T Only
+ case CS_WEAPON_TMP:
+ performBuyWeapon("3", "1");
+ break; // CT Only
+ case CS_WEAPON_MP5NAVY:
+ performBuyWeapon("3", "2");
+ break;
+ case CS_WEAPON_UMP45:
+ performBuyWeapon("3", "3");
+ break;
+ case CS_WEAPON_P90:
+ performBuyWeapon("3", "4");
+ break;
+ //rifles
+ case CS_WEAPON_GALIL:
+ performBuyWeapon("4", "1");
+ break; // T Only
+ case CS_WEAPON_FAMAS:
+ performBuyWeapon("4", "1");
+ break; // CT Only
+ case CS_WEAPON_AK47:
+ performBuyWeapon("4", "2");
+ break; // T Only
+ case CS_WEAPON_M4A1:
+ performBuyWeapon("4", "3");
+ break; // CT Only
+ case CS_WEAPON_SG552:
+ performBuyWeapon("4", "4");
+ break; // T Only
+ case CS_WEAPON_AUG:
+ performBuyWeapon("4", "4");
+ break; // CT Only
+ case CS_WEAPON_SG550:
+ performBuyWeapon("4", "5");
+ break; // CT Only
+ case CS_WEAPON_G3SG1:
+ performBuyWeapon("4", "6");
+ break; // T Only
+ //machinegun
+ case CS_WEAPON_M249:
+ performBuyWeapon("5", "1");
+ break;
+ // equipment
+ case CS_WEAPON_ARMOR_LIGHT:
+ performBuyWeapon("8", "1");
+ break;
+ case CS_WEAPON_ARMOR_HEAVY:
+ performBuyWeapon("8", "2");
+ break;
+ case CS_WEAPON_FLASHBANG:
+ performBuyWeapon("8", "3");
+ break;
+ case CS_WEAPON_HEGRENADE:
+ performBuyWeapon("8", "4");
+ break;
+ case CS_WEAPON_SMOKEGRENADE:
+ performBuyWeapon("8", "5");
+ break;
+ case CS_WEAPON_SHIELD:
+ performBuyWeapon("8", "8");
+ break;
+
+ case CS_DEFUSEKIT:
+ performBuyWeapon("8", "6");
+ break;
+ //default: //Just in case they use pistols but buy MP5 [APG]RoboCop[CL]
+ // performBuyWeapon("3", "2");
+ // break;
+ }
+
+ // This differs per team
+ // FRASHMAN 30/08/04: all into one ifthen block
+ if (iTeam == 2) // counter
+ {
+ switch (weaponIdToBuy) {
+ case CS_WEAPON_SCOUT:
+ performBuyWeapon("4", "2");
+ break;
+ case CS_WEAPON_AWP:
+ performBuyWeapon("4", "6");
+ break;
+ //whats about nightvision? BuyWeapon (pBot, "8", "7")
+ }
+ } else // terror
+ {
+ switch (weaponIdToBuy) {
+ case CS_WEAPON_SCOUT:
+ performBuyWeapon("4", "3");
+ break;
+ case CS_WEAPON_AWP:
+ performBuyWeapon("4", "5");
+ break;
+ //whats about nightvision? BuyWeapon (pBot, "8", "6")
+ }
+ }
+ } // end of cs 1.6 part
+} // We actually gonna buy this weapon
+
+// BOT: Memory()
+// In this function the bot will receive data; this can be any kind of data.
+// For hearing, the bot will check for sounds it should pay attention to and
+// store this into its 'hearing vector'. The hearing vector will be used only
+// when walking and not when fighting an enemy. Do note that this hearing vector
+// is only filled when it is important enough, so all the decisions are made here.
+void cBot::Memory() {
+
+ // Skip method when it is too soon.
+ if (fMemoryTime > gpGlobals->time) {
+ return;
+ }
+
+ // Hear players: (loop through all players, determine if they are running and if
+ // we can hear them (estimated distance)).
+ if (pEnemyEdict == nullptr) {
+ Vector vHear = Vector(9999, 9999, 9999);
+ edict_t* pHearPlayer = nullptr;
+
+ //f_walk_time = gpGlobals->time + 1;
+
+ for (int i = 1; i <= gpGlobals->maxClients; i++) {
+ edict_t* pPlayer = INDEXENT(i);
+
+ // skip invalid players and skip self (i.e. this bot)
+ if (pPlayer && !pPlayer->free && pPlayer != pEdict) {
+ // skip this player if not alive (i.e. dead or dying)
+ if (!IsAlive(pPlayer))
+ continue;
+
+ // check if we can 'see it on radar' (skip teammates)
+ if (UTIL_GetTeam(pPlayer) == UTIL_GetTeam(pEdict))
+ continue;
+
+ // check if its running
+ if (FUNC_PlayerRuns(FUNC_PlayerSpeed(pPlayer))) {
+ // check distance
+ const float fDistance =
+ (pPlayer->v.origin - pEdict->v.origin).Length();
+
+ // estimated distance we can hear somebody
+ if (fDistance < BOT_HEARDISTANCE) {
+ // check if this 'hearing' vector is closer then our previous one
+ if (vHear != Vector(9999, 9999, 9999)) {
+ if (func_distance
+ (pEdict->v.origin,
+ pPlayer->v.origin) <
+ func_distance(pEdict->v.origin, vHear)) {
+ // this one is closer, thus more important
+ vHear = pPlayer->v.origin;
+ pHearPlayer = pPlayer;
+ }
+ } else {
+ vHear = pPlayer->v.origin;
+ pHearPlayer = pPlayer;
+ }
+ }
+ }
+
+ if (pPlayer->v.button & IN_ATTACK
+ && (FUNC_EdictHoldsWeapon(pEdict) != CS_WEAPON_HEGRENADE
+ && FUNC_EdictHoldsWeapon(pEdict) != CS_WEAPON_FLASHBANG
+ && FUNC_EdictHoldsWeapon(pEdict) !=
+ CS_WEAPON_SMOKEGRENADE)) {
+ // check distance
+ const float fDistance =
+ (pPlayer->v.origin - pEdict->v.origin).Length();
+
+ // estimated distance we can hear somebody
+ if (fDistance < BOT_HEARFIREDISTANCE) {
+ // check if this 'hearing' vector is closer then our previous one
+ if (vHear != Vector(9999, 9999, 9999)) {
+ if (func_distance
+ (pEdict->v.origin,
+ pPlayer->v.origin) <
+ func_distance(pEdict->v.origin, vHear)) {
+ // this one is closer, thus more important
+ vHear = pPlayer->v.origin;
+ pHearPlayer = pPlayer;
+ }
+ } else {
+ vHear = pPlayer->v.origin;
+ pHearPlayer = pPlayer;
+ }
+ }
+ }
+ // zooming of a sniper rifle
+ if (pPlayer->v.button & IN_ATTACK2) {
+ // check distance
+ const float fDistance =
+ (pPlayer->v.origin - pEdict->v.origin).Length();
+
+ // estimated distance we can hear somebody
+ if (fDistance < BOT_HEARDISTANCE) {
+ // check if this 'hearing' vector is closer then our previous one
+ if (vHear != Vector(9999, 9999, 9999)) {
+ if (func_distance
+ (pEdict->v.origin,
+ pPlayer->v.origin) <
+ func_distance(pEdict->v.origin, vHear)) {
+ // this one is closer, thus more important
+ vHear = pPlayer->v.origin;
+ pHearPlayer = pPlayer;
+ }
+ } else {
+ vHear = pPlayer->v.origin;
+ pHearPlayer = pPlayer;
+ }
+ }
+ }
+
+ }
+ }
+
+ // Fill in hearing vectory if any:
+ if (pHearPlayer != nullptr) {
+ if (RANDOM_LONG(0, 100) < ipFearRate + 10) {
+
+ // determine fuzzyness by distance:
+ int iFuzz =
+ static_cast(func_distance(pEdict->v.origin, vHear) /
+ BOT_HEARDISTANCE) * 250;
+
+ // skill depended
+ iFuzz /= bot_skill + 1;
+
+ // create 'estimated hear vector'
+ const float randX = RANDOM_LONG(-iFuzz, iFuzz);
+ const float randY = RANDOM_LONG(-iFuzz, iFuzz);
+ const float randZ = RANDOM_LONG(-iFuzz, iFuzz);
+
+ vHear = vHear + Vector(randX, randY, randZ);
+
+ TraceResult tr;
+
+ UTIL_TraceHull(pEdict->v.origin, vHear, dont_ignore_monsters,
+ point_hull, pEdict, &tr);
+
+ int iNodeHearPlayer =
+ NodeMachine.getClosestNode(vHear, NODE_ZONE * 2, pHearPlayer);
+
+ // if nothing hit:
+ if (tr.flFraction >= 1.0f) {
+ // we can look at this spot
+ vEar = vHear;
+ }
+ // we go to the destination
+
+ const float fTime = 5 + static_cast(ipFearRate) / static_cast(7);
+
+ if (RANDOM_LONG(0, 100) < ipFearRate
+ && f_walk_time + 5 < gpGlobals->time) // last 5 seconds did not walk
+ f_walk_time = gpGlobals->time + fTime;
+
+ if (RANDOM_LONG(0, 100) < ipCampRate
+ && f_camp_time + 30 < gpGlobals->time // last 30 seconds did not camp
+ ) {
+ f_camp_time = gpGlobals->time + fTime;
+ }
+
+ } else {
+ fMemoryTime = gpGlobals->time + 5.0f;
+ }
+
+ /*
+
+
+ int iNodeHearPlayer = NodeMachine.getCloseNode (vHear, NODE_ZONE*2, pHearPlayer);
+ int iNodeFrom = NodeMachine.getCloseNode (pEdict->v.origin, NODE_ZONE*2, pEdict);
+ int iHearToNode = NodeMachine.node_look_at_hear(iNodeHearPlayer, iNodeFrom, pEdict);
+
+ // look at hearto node
+ if (iHearToNode > -1)
+ {
+ vHead = NodeMachine.node_vector(iHearToNode);
+ SERVER_PRINT("found smart look at node\n");
+ }
+
+ // only check for new goal when the current goal is way of distance and such
+ if (ipCampRate > 30 && f_camp_time + 5 < gpGlobals->time)
+ f_camp_time = gpGlobals->time + 2.5;
+ */
+
+ if (f_update_weapon_time + 2 < gpGlobals->time) {
+ PickBestWeapon();
+ }
+ } else {
+ vEar = Vector(9999, 9999, 9999);
+ //
+ // // check for any 'beeps' of the bomb!
+ // if (isCounterTerrorist() && Game.bBombPlanted) {
+ // // find the bomb vector
+ // edict_t *pent = NULL;
+ // Vector vC4 = Vector(9999, 9999, 9999);
+ // while ((pent = UTIL_FindEntityByClassname(pent, "grenade")) != NULL) {
+ // if (UTIL_GetGrenadeType(pent) == 4) // It is a C4
+ // {
+ // vC4 = pent->v.origin; // store origin
+ // break; // done our part now
+ // }
+ // } // --- find the c4
+ //
+ // if (vC4 != Vector(9999, 9999, 9999)) {
+ //
+ // if (func_distance(vC4, NodeMachine.node_vector(iGoalNode)) > 100 &&
+ // func_distance(pEdict->v.origin, vC4) < 1024) {
+ // // set new goal node
+ // setGoalNode(NodeMachine.getCloseNode(vC4, NODE_ZONE, NULL));
+ // forgetPath();
+ // }
+ // }
+ // }
+ }
+ } else {
+ vEar = Vector(9999, 9999, 9999);
+ }
+}
+
+void cBot::Walk() //Experimental implementation [APG]RoboCop[CL]
+{
+ if (f_walk_time + 0.1f < gpGlobals->time) {
+ f_walk_time = gpGlobals->time + 0.1f;
+ if (f_walk_time + 0.1f < gpGlobals->time) {
+ f_walk_time = gpGlobals->time + 0.1f;
+ }
+ }
+}
+
+
+// BOT: Do i carry weapon # now?
+bool cBot::CarryWeapon(const int iType) const
+{
+ if (current_weapon.iId == iType)
+ return true;
+ return false;
+}
+
+// BOT: Do i carry weapon TYPE # now?
+int cBot::CarryWeaponType() const
+{
+ int kind = PRIMARY;
+ const int weapon_id = current_weapon.iId;
+
+ // Check 1. Is it a knife?
+ if (weapon_id == CS_WEAPON_KNIFE)
+ kind = KNIFE;
+
+ // Check 2, is it a 'tool'?
+ if (weapon_id == CS_WEAPON_FLASHBANG || weapon_id == CS_WEAPON_HEGRENADE
+ || weapon_id == CS_WEAPON_SMOKEGRENADE)
+ kind = GRENADE;
+
+ // Check 3, is it a secondary gun?
+ if (weapon_id == CS_WEAPON_P228 || weapon_id == CS_WEAPON_ELITE
+ || weapon_id == CS_WEAPON_USP || weapon_id == CS_WEAPON_GLOCK18
+ || weapon_id == CS_WEAPON_DEAGLE || weapon_id == CS_WEAPON_FIVESEVEN)
+ kind = SECONDARY;
+
+ // Check 4, is it a sniper gun?
+ if (weapon_id == CS_WEAPON_SCOUT || weapon_id == CS_WEAPON_SG550
+ || weapon_id == CS_WEAPON_AWP || weapon_id == CS_WEAPON_G3SG1)
+ kind = SNIPER;
+
+ if (hasShield()) {
+ kind = SHIELD;
+ }
+ //if (weapon_id < 1)
+ // kind = NONE;
+ return kind;
+}
+
+// BOT: Think about objectives
+//
+// This function only takes action when the bot is close a goal. The function
+// NodeMachine.path_think() handles WHERE the bot goes. Not WHAT to do at a goal.
+void cBot::ThinkAboutGoals() {
+ //REALBOT_PRINT(this, "thinkAboutGoals()", "start");
+ // Depending on bot team we handle goals differently:
+ // TERRORISTS
+ if (isTerrorist()) {
+ // Plant the bomb when the HUD says we can -- BERKED
+ if (bHUD_C4_plantable)
+ f_c4_time = gpGlobals->time + 1; // plant bomb
+
+ // A dropped C4 is not a 'goal' (ie. it won't let you win the game
+ // when you pick up the bomb. Therefor the 'pickup the dropped bomb
+ // code is in cNodeMachine::path_walk().
+ } else if (isCounterTerrorist()) {
+ // COUNTER-TERRORISTS
+ if (vip) {
+ // VIP
+ } else {
+ if (Game.bBombPlanted) {
+ if (isCounterTerrorist()) {
+ // defuse (or set timers for it)
+ Defuse();
+ }
+ } else {
+ if (Game.bHostageRescueMap) {
+ TryToGetHostageTargetToFollowMe(this);
+ checkIfHostagesAreRescued();
+ checkOfHostagesStillFollowMe();
+ }
+ }
+ }
+ }
+ // in Act() we find the 'acting' code when timers above are set.
+}
+
+void cBot::rememberWhichHostageToRescue(edict_t* pHostage) {
+ this->pBotHostage = pHostage;
+}
+
+edict_t* cBot::getHostageToRescue() const
+{
+ return pBotHostage;
+}
+
+edict_t* cBot::findHostageToRescue() {
+ edict_t* pent = nullptr;
+
+ // Search for all hostages in the game
+ while ((pent = UTIL_FindEntityByClassname(pent, "hostage_entity")) != nullptr) {
+ if (!isHostageRescueable(this, pent)) continue;
+ if (!canSeeEntity(pent)) continue;
+ // skip too far hostages, leave it up to the goal picking to get closer
+ if (getDistanceTo(pent->v.origin) > static_cast(NODE_ZONE) * 2.5f) continue;
+
+ char msg[255];
+ snprintf(msg, sizeof(msg), "Found hostage to rescue at %f,%f,%f", pent->v.origin.x, pent->v.origin.y, pent->v.origin.z);
+ this->rprint_trace("findHostageToRescue()", msg);
+ return pent;
+ }
+
+ return nullptr;
+}
+
+bool cBot::isDefusing() const
+{
+ return f_defuse > gpGlobals->time;
+}
+
+bool cBot::hasTimeToMoveToNode() const
+{
+ return fMoveToNodeTime > -1 && getMoveToNodeTimeRemaining() > 0;
+}
+/**
+This function will set the iCloseNode variable, which is the node most closest to
+the bot. Returns the closest node it found.
+**/
+int cBot::determineCurrentNode() {
+ iCloseNode = determineCurrentNode(NODE_ZONE);
+ return iCloseNode;
+}
+
+/**
+This function will set the iCloseNode variable, which is the node most closest to
+the bot. Returns the closest node it found.
+**/
+int cBot::determineCurrentNodeWithTwoAttempts() {
+ iCloseNode = determineCurrentNode();
+ if (iCloseNode < 0) {
+ iCloseNode = determineCurrentNode(NODE_ZONE * 2);
+ }
+ return iCloseNode;
+}
+
+/**
+Find node close to bot, given range. Does not cache result.
+**/
+int cBot::determineCurrentNode(const float range) const
+{
+ return NodeMachine.getClosestNode(pEdict->v.origin, range, pEdict);
+}
+
+/**
+ * This returns the current node (iCloseNode) set. Instead of using determineCurrentNode, which is expensive,
+ * call this to return the cached value. It will however call determineCurrentNode when node is < 0, usually it means
+ * the state has been set.
+ * @return
+ */
+int cBot::getCurrentNode() {
+ if (iCloseNode < 0) {
+ determineCurrentNode();
+ }
+ return iCloseNode;
+}
+
+/**
+ * Aka, the node we are heading for.
+ */
+int cBot::getCurrentPathNodeToHeadFor() const
+{
+ return NodeMachine.getNodeIndexFromBotForPath(iBotIndex, pathIndex);
+}
+
+/**
+ * Aka, the node we were coming from. In case the index is < 0 (ie, there is no previous node yet), this will
+ * return -1;
+ */
+int cBot::getPreviousPathNodeToHeadFor() const
+{
+ return NodeMachine.getNodeIndexFromBotForPath(iBotIndex, getPreviousPathIndex());
+}
+
+bool cBot::isHeadingForGoalNode() const
+{
+ return getCurrentPathNodeToHeadFor() == getGoalNode();
+}
+
+/**
+ * Aka, the next node after we have arrived at the current path node.
+ */
+int cBot::getNextPathNode() const
+{
+ return NodeMachine.getNodeIndexFromBotForPath(iBotIndex, pathIndex + 1);
+}
+
+// Is this bot dead?
+bool cBot::isDead() const
+{
+ return pEdict->v.health < 1 || pEdict->v.deadflag != DEAD_NO;
+}
+
+// BOT: Think
+void cBot::Think() {
+ if (mod_id != CSTRIKE_DLL) return; // do not support non-counter-strike mods
+
+ // BOT: If a bot did not join a team yet, then do it
+ if (!hasJoinedTeam) {
+ rprint("Need to join team, doing that now");
+ JoinTeam();
+ return;
+ }
+
+ // Set closest node
+ determineCurrentNode();
+
+ // BOT: If a bot is dead, re-initialize
+ if (isDead()) {
+ if (!bInitialize) return; // do nothing when no need to initialize
+ rprint("Dead, need to re-initialize");
+
+ // AUTOSKILL
+ const cBot* botPointerOfKiller = UTIL_GetBotPointer(killer_edict);
+
+ // not killed by a fellow bot, presumably a human player
+ if (botPointerOfKiller == nullptr) {
+ if (autoskill) {
+ bot_skill--;
+ bot_skill = std::max(bot_skill, 0);
+ }
+
+ if (Game.iKillsBroadcasting != BROADCAST_KILLS_NONE
+ && killer_edict != nullptr) {
+ // This is a human, we will tell this human he has been killed
+ // by a bot.
+ const int r = RANDOM_LONG(150, 255);
+ const int g = RANDOM_LONG(30, 155);
+ const int b = RANDOM_LONG(30, 155);
+ char msg[128];
+ if (Game.iDeathsBroadcasting == BROADCAST_DEATHS_FULL) {
+ snprintf(msg, sizeof(msg), "A RealBot has killed you!\n\nName:%s\nSkill:%d\n", name, bot_skill);
+ }
+ else {
+ snprintf(msg, sizeof(msg), "A RealBot named %s has killed you!", name);
+ }
+
+ HUD_DrawString(r, g, b, msg, killer_edict);
+ }
+ }
+
+ if (iCloseNode > -1 && !end_round) {
+ iDiedNode = iCloseNode;
+ NodeMachine.danger(iCloseNode, UTIL_GetTeam(pEdict));
+ }
+
+ if (console_nr == 0) {
+ rprint("NewRound - because console_nr ?!");
+ NewRound();
+ bInitialize = false;
+ }
+
+ BotConsole(this);
+
+ // dead messages
+ if (console_nr == 0) {
+ rprint("console_nr == 0"); //whatever this means
+ // do some chatting
+ if (RANDOM_LONG(0, 200) < ipChatRate) {
+ if (fChatTime + 0.5f < gpGlobals->time)
+ if (chChatSentence[0] == '\0') // we did not want to say anything
+ {
+ // we should say something now?
+ int iMax = -1;
+
+ for (const char(&tc)[128] : ChatEngine.ReplyBlock[99].sentence)
+ {
+ if (tc[0] != '\0') iMax++;
+ }
+
+ const int the_c = RANDOM_LONG(0, iMax);
+
+ if (the_c > -1 && iMax > -1) {
+ char chSentence[80] = {};
+ snprintf(chSentence, sizeof(chSentence),
+ "%s ", ChatEngine.ReplyBlock[99].sentence[the_c]);
+ //strcpy(chSentence, ChatEngine.ReplyBlock[99].sentence[the_c]);
+ PrepareChat(chSentence);
+ }
+ }
+ }
+ else {
+ // we missed the chatrate chance
+ if (fChatTime < gpGlobals->time) // time
+ if (chChatSentence[0] == '\0') // we did not want to say anything
+ if (RANDOM_LONG(0, 100) < ipChatRate) // rate
+ fChatTime = gpGlobals->time +
+ RANDOM_FLOAT(0.0f, (Game.iProducedSentences + 1.0f) / 2.0f); // wait
+
+ }
+
+ return;
+ }
+ } // isDead();
+
+ // set this for the next time the bot dies so it will initialize stuff
+ if (!bInitialize) {
+ bInitialize = true;
+ }
+
+ if (end_round) {
+ rprint("End round");
+ MDLL_ClientKill(pEdict);
+ pEdict->v.frags += 1;
+ return;
+ }
+
+ // BOT: Played enough rounds
+ if (played_rounds > play_rounds && internet_play) {
+ rprint("Played enough rounds");
+ bIsUsed = false; // no longer used
+ char cmd[80];
+ snprintf(cmd, sizeof(cmd), "kick \"%s\"\n", name);
+ SERVER_COMMAND(cmd); // kick the bot using (kick "name")
+ return;
+ }
+
+ // Move speed... moved_distance.
+ if (distanceMovedTimer <= gpGlobals->time) {
+ // see how far bot has moved since the previous position...
+ const Vector v_diff = prevOrigin - pEdict->v.origin;
+ // make distanceMoved an average of this moment and the previous one.
+ const float movedTwoTimes = distanceMoved + v_diff.Length();
+
+ // prevent division by zero
+ if (movedTwoTimes > 0.0f) {
+ distanceMoved = movedTwoTimes / 2.0f;
+ }
+ else {
+ distanceMoved = 0.0f;
+ }
+
+ // save current position as previous
+ prevOrigin = pEdict->v.origin;
+ distanceMovedTimer = gpGlobals->time + 0.1f;
+ }
+
+ // NEW ROUND
+ if (Game.NewRound()) {
+ rprint_trace("Think", "Game.NewRound");
+ }
+
+ // --------------------------------
+ // MEMORY STEP
+ // --------------------------------
+ Memory();
+
+ // --------------------------------
+ // IMPORTANT THINKING GOING ON HERE
+ // --------------------------------
+ const int healthChange = prev_health - bot_health;
+
+ // handle damage taken
+ if (prev_health > bot_health
+ && healthChange > RANDOM_LONG(CSTRIKE_MIN_DAMAGE, CSTRIKE_MAX_DAMAGE)
+ && hasEnemy()) {
+
+ // need backup!
+ if (FUNC_DoRadio(this)) {
+ UTIL_BotRadioMessage(this, 3, "3", "");
+ }
+
+ BOT_DecideTakeCover(this);
+ }
+
+ prev_health = bot_health;
+
+ // Do your console stuff
+ BotConsole(this);
+
+ // BOT: Blinded
+ if (isBlindedByFlashbang()) {
+ // Dude we are messed up.
+
+ // 01/07/04 - Stefan - Pointed out on the forums by Josh Borke... (do not shoot when dontshoot is on)
+ // shoot randomly
+ if (!Game.bDoNotShoot) {
+ if (RANDOM_LONG(0, 100) < ipFearRate && RANDOM_LONG(0, 100)) {
+ UTIL_BotPressKey(this, IN_ATTACK);
+ }
+ }
+
+ rprint_trace("Think()", "Blinded");
+ return;
+ }
+
+ // NEW: When round time is over and still busy playing, kill bots
+ const float roundTimeInSeconds = CVAR_GET_FLOAT("mp_roundtime") * 60.0f;
+ const float freezeTimeCVAR = CVAR_GET_FLOAT("mp_freezetime");
+ if (Game.getRoundStartedTime() + 10.0f + roundTimeInSeconds + freezeTimeCVAR < gpGlobals->time) {
+ end_round = true;
+ // round is ended
+ }
+
+ // FREEZETIME:
+ if (Game.getRoundStartedTime() > gpGlobals->time && freezeTime < gpGlobals->time) {
+ freezeTime = gpGlobals->time + RANDOM_FLOAT(0.1f, 2.0f);
+ }
+
+ // 1 SECOND START OF ROUND
+ if (!bIssuedInitialRadio &&
+ Game.getRoundStartedTime() < gpGlobals->time &&
+ Game.getRoundStartedTime() + 1.0f > gpGlobals->time) {
+ if (RANDOM_LONG(0, 100) < 30 && FUNC_DoRadio(this)) {
+ UTIL_BotRadioMessage(this, 2, "1", ""); // "Go, Go, Go!"
+ }
+ bIssuedInitialRadio = true;
+ this->rprint_trace("cBot::Think()", "First second of round, issued initial radio.");
+ }
+
+ // SITUATION: In freezetime
+ if (isFreezeTime()) {
+ stopMoving();
+ lastSeenEnemyVector = Vector(0, 0, 0);
+ setTimeToMoveToNode(2);
+ vHead = vBody = pEdict->v.origin;
+
+ // find any spawnpoint to look at:
+ edict_t* pent = nullptr;
+
+ if (isCounterTerrorist()) {
+ while ((pent = UTIL_FindEntityByClassname(pent, "info_player_start")) != nullptr) {
+ if (func_distance(pent->v.origin, pEdict->v.origin) < 200 &&
+ func_distance(pent->v.origin, pEdict->v.origin) > 50) {
+ break;
+ }
+ }
+ }
+ else {
+ while ((pent = UTIL_FindEntityByClassname(pent, "info_player_deathmatch")) != nullptr) {
+ if (func_distance(pent->v.origin, pEdict->v.origin) < 200 &&
+ func_distance(pent->v.origin, pEdict->v.origin) > 50) {
+ break;
+ }
+ }
+ }
+
+ // when pent is filled, look at it
+ if (pent != nullptr) {
+ vBody = vHead = pent->v.origin;
+ }
+
+ rprint_trace("Think()", "isFreezeTime");
+ return;
+ }
+
+ // Check if bot is stuck
+ if (fNotStuckTime < gpGlobals->time)
+ {
+ if (isStuck())
+ {
+ // The bot is stuck, find a breakable if it's in the way
+ FUNC_FindBreakable(this);
+ if (pBreakableEdict != nullptr)
+ {
+ // Found a breakable, attack it
+ FUNC_AttackBreakable(this);
+ // Reset stuck timer
+ fNotStuckTime = gpGlobals->time + 2.0f;
+ return;
+ }
+ }
+ else
+ {
+ // Bot is not stuck, reset stuck timer
+ fNotStuckTime = gpGlobals->time + 2.0f;
+ }
+ }
+
+ // If the bot has a breakable target, attack it immediately.
+ if (pBreakableEdict != nullptr) {
+ FUNC_AttackBreakable(this);
+ return;
+ }
+
+ // **---**---**---**---**---**---**
+ // MAIN STATE: We have no enemy...
+ // **---**---**---**---**---**---**
+ if (!hasEnemy()) {
+
+ if (!Game.bDoNotShoot) {
+ FUNC_FindBreakable(this);
+ // If a breakable is found, the next think cycle will handle it
+ if (pBreakableEdict == nullptr) {
+ InteractWithPlayers();
+ }
+ }
+
+ bool bMayFromGame = true;
+
+ if (Game.fWalkWithKnife > 0.0f)
+ if (Game.getRoundStartedTime() + Game.fWalkWithKnife < gpGlobals->time)
+ bMayFromGame = false;
+
+ if (Game.fWalkWithKnife == 0.0f)
+ bMayFromGame = false;
+
+ if (hasShield()) {
+ if (!hasShieldDrawn() && f_allow_keypress < gpGlobals->time) {
+ UTIL_BotPressKey(this, IN_ATTACK2); // draw shield
+ f_allow_keypress = gpGlobals->time + 0.7f;
+ }
+ }
+
+ if (CarryWeapon(CS_WEAPON_KNIFE) == false
+ && f_camp_time < gpGlobals->time
+ && freezeTime < gpGlobals->time
+ && f_c4_time < gpGlobals->time
+ && f_update_weapon_time < gpGlobals->time && bWalkKnife
+ && bMayFromGame) {
+ UTIL_SelectItem(pEdict, UTIL_GiveWeaponName(-1)); // -1 is knife
+ f_update_weapon_time = gpGlobals->time + 0.7f;
+ }
+
+ // When holding a grenade (and not switching to another weapon)
+ if (CarryWeaponType() == GRENADE
+ && f_update_weapon_time < gpGlobals->time) {
+ if (iPrimaryWeapon > -1)
+ UTIL_SelectItem(pEdict,
+ UTIL_GiveWeaponName(iPrimaryWeapon));
+
+ else // pick secondary
+ UTIL_SelectItem(pEdict,
+ UTIL_GiveWeaponName(iSecondaryWeapon));
+ f_update_weapon_time = gpGlobals->time + 0.7f;
+ }
+
+ // Think about objectives
+ ThinkAboutGoals();
+ }
+ else {
+ // **---**---**---**---**---**---**
+ // MAIN STATE: We have an enemy!
+ // **---**---**---**---**---**---**
+
+ // Keep interacting with players:
+ InteractWithPlayers();
+
+ // And combat enemies
+ Combat();
+ }
+
+ // WALK()
+ NodeMachine.path_think(this, distanceMoved);
+
+ // SITUATION: Passed Freezetime
+
+} // THINK()
+
+bool cBot::isFreezeTime() const {
+ return freezeTime > gpGlobals->time;
+}
+
+/**
+Return true if one of the pointers is not NULL
+**/
+bool cBot::isEscortingHostages() {
+ const bool result = getAmountOfHostagesBeingRescued() > 0;
+ if (result) {
+ rprint("I am escorting hostages!");
+ }
+ return result;
+}
+
+void cBot::checkOfHostagesStillFollowMe() {
+ if (fCheckHostageStatusTimer > gpGlobals->time) return;
+ fCheckHostageStatusTimer = gpGlobals->time + 5.0f;
+
+ //// this->rprint("checkOfHostagesStillFollowMe - START");
+ // if (hostage1) {
+ // if (!isHostageRescued(this, hostage1) && FUNC_EdictIsAlive(hostage1) && !canSeeEntity(hostage1) && getDistanceTo(hostage1->v.origin) > NODE_ZONE*2.5) {
+ // rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage1");
+ // forgetHostage(hostage1);
+ // }
+ // }
+ // if (hostage2) {
+ // if (!isHostageRescued(this, hostage2) && FUNC_EdictIsAlive(hostage2) && !canSeeEntity(hostage2) && getDistanceTo(hostage2->v.origin) > NODE_ZONE*2.5) {
+ // rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage2");
+ // forgetHostage(hostage2);
+ // }
+ // }
+ // if (hostage3) {
+ // if (!isHostageRescued(this, hostage3) && FUNC_EdictIsAlive(hostage3) && !canSeeEntity(hostage3) && getDistanceTo(hostage3->v.origin) > NODE_ZONE*2.5) {
+ // rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage3");
+ // forgetHostage(hostage3);
+ // }
+ // }
+ //
+ // if (hostage4) {
+ // if (!isHostageRescued(this, hostage4) && FUNC_EdictIsAlive(hostage4) && !canSeeEntity(hostage4) && getDistanceTo(hostage4->v.origin) > NODE_ZONE*2.5) {
+ // rprint_trace("checkOfHostagesStillFollowMe", "lost track of hostage4");
+ // forgetHostage(hostage4);
+ // }
+ // }
+ // rprint("checkOfHostagesStillFollowMe - END");
+}
+
+void cBot::clearHostages() {
+ rprint_trace("clearHostages");
+ hostage1 = nullptr;
+ hostage2 = nullptr;
+ hostage3 = nullptr;
+ hostage4 = nullptr;
+ pBotHostage = nullptr;
+}
+
+// BOT: CheckGear, part of UpdateStatus()
+void cBot::CheckGear() {
+
+ // PRIMARY
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_mp5navy"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_mp5navy");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_ak47"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_ak47");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_m3"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_m3");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_aug"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_aug");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_sg552"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_sg552");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_m249"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_m249");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_xm1014"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_xm1014");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_p90"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_p90");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_tmp"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_tmp");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_m4a1"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_m4a1");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_awp"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_awp");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_sg550"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_sg550");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_scout"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_scout");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_mac10"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_mac10");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_g3sg1"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_g3sg1");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_ump45"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_ump45");
+
+ // Counter-Strike 1.6 weapon FAMAS/GALIL
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_famas"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_famas");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_galil"))) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_galil");
+
+ // SECONDARY
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_elite"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_elite");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_fiveseven"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_fiveseven");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_p228"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_p228");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_deagle"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_deagle");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_usp"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_usp");
+ if (isOwningWeapon(UTIL_GiveWeaponId("weapon_glock18"))) iSecondaryWeapon = UTIL_GiveWeaponId("weapon_glock18");
+
+ // Handle shields as primary weapon
+ if (hasShield()) iPrimaryWeapon = UTIL_GiveWeaponId("weapon_shield");
+}
+
+// BOT: Update personal status
+void cBot::UpdateStatus() {
+ // name filled in yet?
+ if (name[0] == 0)
+ std::strcpy(name, STRING(pEdict->v.netname));
+
+ // Set thirdpartybot flag
+ pEdict->v.flags |= FL_THIRDPARTYBOT;
+
+ // Reset stuff
+ pEdict->v.button = 0;
+ setMoveSpeed(f_max_speed); // by default run
+
+ // When its not time to strafe, don't.
+ if (f_strafe_time < gpGlobals->time) {
+ if (f_strafe_speed != 0.0f) {
+ rprint_trace("UpdateStatus", "Strafe speed set to 0!");
+ f_strafe_speed = 0.0f;
+ }
+ }
+
+ // Update team state when started
+ if (hasJoinedTeam) {
+ iTeam = UTIL_GetTeam(pEdict) + 1; // 1 - TERRORIST, 2 - COUNTER-TERRORIST
+ }
+
+ // Check if we became VIP
+ vip = UTIL_IsVip(pEdict);
+
+ // Check gear
+ CheckGear();
+
+ // Set max speed and such when CS 1.6
+ if (counterstrike == 1) {
+ f_max_speed = pEdict->v.maxspeed;
+ // char msg[255];
+ // sprintf(msg, "f_max_speed set to %f", f_max_speed);
+ // rprint_trace("UpdateStatus", msg);
+ bot_health = static_cast(pEdict->v.health);
+ bot_armor = static_cast(pEdict->v.armorvalue);
+ }
+}
+
+// ---------------------------------- BOT CLASS FUNCTIONS
+// ---------------------------------- BOT CLASS FUNCTIONS
+// ---------------------------------- BOT CLASS FUNCTIONS
+
+////////////////////////////////////////////////////////////////////////////////
+/// Radio Action - Response
+////////////////////////////////////////////////////////////////////////////////
+bool BotRadioAction() {
+ char name[64];
+ bool unstood = false;
+ edict_t* plr = nullptr;
+ int team = -1;
+ int i;
+ int radios = 0; // Hold amount of replies here, so we don't flood :)
+ std::strcpy(name, radio_messenger);
+
+ // First find the team messager name
+ for (i = 1; i <= gpGlobals->maxClients; i++) {
+ edict_t* pPlayer = INDEXENT(i); // Get pEdict
+ if (pPlayer) // If player exists
+ {
+ char netname[64];
+ std::strcpy(netname, STRING(pPlayer->v.netname)); // Copy netname
+ if (std::strcmp(netname, name) == 0) // If
+ {
+ plr = pPlayer;
+ team = UTIL_GetTeam(pPlayer);
+ }
+ }
+ }
+
+ // Check players and check if radio message applies to them
+ for (i = 1; i <= gpGlobals->maxClients; i++) {
+ edict_t* pPlayer = INDEXENT(i);
+ if (pPlayer) {
+ char netname[64];
+
+ std::strcpy(netname, STRING(pPlayer->v.netname));
+
+ if (std::strcmp(netname, name) != 0 && // When not the same name
+ team == UTIL_GetTeam(pPlayer) && // .. the same team...
+ pPlayer->v.deadflag == DEAD_NO && // .. not dead ..
+ UTIL_GetBotPointer(pPlayer) != nullptr) // and a RealBot
+ {
+ // here are all bots
+ cBot* BotPointer = UTIL_GetBotPointer(pPlayer);
+
+ if (BotPointer == nullptr)
+ continue; // somehow this fucked up, bail out
+
+ const float distance = func_distance(plr->v.origin,
+ BotPointer->pEdict->v.origin); // distance between the 2
+
+ // Same team, randomly, do we even listen to the radio?
+ // the more further away, the more chance it will not listen
+ bool bWantToListen = false;
+
+ // Reply on distance check
+ if (RANDOM_LONG(0, 8192) > distance)
+ bWantToListen = true;
+
+ // Hearrate (personality setting)
+ if (RANDOM_LONG(0, 100) < BotPointer->ipHearRate &&
+ bWantToListen)
+ bool want_to_answer = true;
+
+ // If we want to listen to the radio... then handle it!
+ if (bWantToListen) {
+ bool can_do_negative = false;
+
+ // Report in team!
+ if (std::strstr(message, "#Report_in_team") != nullptr) {
+ // gives human knowledge who is on his team
+ }
+
+ // Regroup team!
+ if (std::strstr(message, "#Regroup_team") != nullptr) {
+ // regroup now!
+ unstood = true;
+
+ // get to the leader position
+ BotPointer->rprint("Setting goal from regroup team");
+ BotPointer->setGoalNode(NodeMachine.getClosestNode(plr->v.origin, NODE_ZONE * 2, plr));
+ BotPointer->forgetPath();
+ }
+
+ // Hold this position
+ if (std::strstr(message, "#Hold_this_position") != nullptr ||
+ std::strstr(message, "#Get_in_position_and_wait") != nullptr) {
+ // do nothing
+ }
+ // Follow me!!
+ if (std::strstr(message, "#Follow_me") != nullptr) {}
+
+ // You take the point!
+ // 23/06/04 - Stefan - Here the leader should break up his position?
+ // ie, the leader will be assigned to the bot this human/bot is facing?
+ if (std::strstr(message, "#You_take_the_point") != nullptr) {
+ can_do_negative = false;
+ }
+ // Enemy Sotted!
+ if (std::strstr(message, "#Enemy_spotted") != nullptr) {
+ can_do_negative = false;
+
+ // Find player who issues this message and go to it
+ const int iBackupNode =
+ NodeMachine.getClosestNode(plr->v.origin, NODE_ZONE, plr);
+
+ // Help this player
+ if (iBackupNode > -1) {
+
+ unstood = true;
+
+ BotPointer->rprint("Setting goal for backup");
+ BotPointer->setGoalNode(iBackupNode);
+ BotPointer->forgetPath();
+ BotPointer->f_camp_time = gpGlobals->time - 1;
+ BotPointer->f_walk_time = gpGlobals->time;
+ }
+ }
+ // Enemy Down!
+ if (std::strstr(message, "#Enemy_down") != nullptr) {
+ BotPointer->rprint_trace("BotRadioAction", "Understood Enemy down - no logic");
+
+ unstood = true;
+ can_do_negative = false;
+ }
+ // Stick together team!
+ if (std::strstr(message, "#Stick_together_team") != nullptr) {
+ BotPointer->rprint_trace("BotRadioAction", "Understood Stick together team - no logic");
+ unstood = true;
+ can_do_negative = false;
+ }
+ // cover me|| strstr (message, "#Cover_me") != NULL
+
+ // Need backup / taking fire...
+ if (std::strstr(message, "#Need_backup") != nullptr || std::strstr(message, "#Taking_fire") != nullptr) {
+ BotPointer->rprint_trace("BotRadioAction", "Understood Need backup or Taking fire");
+
+ unstood = true;
+
+ // get source of backup
+ const int iBackupNode = NodeMachine.getClosestNode(plr->v.origin, NODE_ZONE, plr);
+
+ if (iBackupNode > -1) {
+ BotPointer->rprint_trace("BotRadioAction", "Found node nearby player who requested backup/reported taking fire.");
+ BotPointer->setGoalNode(iBackupNode);
+ BotPointer->forgetPath();
+ BotPointer->f_camp_time = gpGlobals->time - 1;
+ BotPointer->f_walk_time = gpGlobals->time;
+ }
+ }
+
+ // Taking fire!
+ if (std::strstr(message, "#Taking_fire") != nullptr) {
+ BotPointer->rprint_trace("BotRadioAction", "Understood Taking fire");
+ unstood = true;
+
+ // Find player who issued this message and go to it
+ const int iBackupNode =
+ NodeMachine.getClosestNode(plr->v.origin, NODE_ZONE, plr);
+
+ if (iBackupNode > -1) {
+ BotPointer->rprint_trace("BotRadioAction", "Found node nearby player who requested backup/reported taking fire.");
+ BotPointer->setGoalNode(iBackupNode);
+ BotPointer->forgetPath();
+ BotPointer->f_camp_time = gpGlobals->time - 1;
+ BotPointer->f_walk_time = gpGlobals->time;
+ }
+
+ }
+ // Team fall back!
+ if (std::strstr(message, "#Team_fall_back") != nullptr) {
+
+ }
+ // Go Go Go, stop camping, stop following, get the heck out of there!
+ if (std::strstr(message, "#Go_go_go") != nullptr) {
+ BotPointer->rprint_trace("BotRadioAction", "Understood Go Go Go");
+ unstood = true;
+ BotPointer->f_camp_time = gpGlobals->time - 30;
+ BotPointer->f_walk_time = gpGlobals->time;
+ BotPointer->f_cover_time = gpGlobals->time - 10;
+ BotPointer->f_hold_duck = gpGlobals->time - 10;
+ BotPointer->f_jump_time = gpGlobals->time - 10;
+ BotPointer->forgetPath();
+ BotPointer->forgetGoal();
+ }
+
+ if (FUNC_DoRadio(BotPointer) && unstood) {
+ const int maxAllowedRadios = gpGlobals->maxClients / 4;
+ if (BotPointer->console_nr == 0 && radios < maxAllowedRadios) {
+ constexpr bool report_back = false;
+
+ if constexpr (!report_back) {
+ UTIL_BotRadioMessage(BotPointer, 3, "1", ""); // Roger that!
+ }
+ else {
+ UTIL_BotRadioMessage(BotPointer, 3, "6", ""); // Reporting in!
+ }
+
+ BotPointer->f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.8f, 2.0f);
+ radios++;
+ }
+ }
+ } // they even listen to the radio command?
+ else {
+ /*
+ // filter out the commands where we cannot reply with negative
+ // You take the point!
+ if (strstr (message, "#You_take_the_point") != NULL)
+ can_do_negative = false;
+
+ // Enemy Sotted!
+ if (strstr (message, "#Enemy_spotted") != NULL)
+ can_do_negative = false;
+
+ // Enemy Down!
+ if (strstr (message, "#Enemy_down") != NULL)
+ can_do_negative = false;
+
+ if ((FUNC_DoRadio(BotPointer))
+ && (unstood) && (can_do_negative))
+
+ {
+ if (BotPointer->console_nr == 0
+ && radios < (gpGlobals->maxClients / 4))
+
+ {
+ if (report_back == false)
+
+ {
+ UTIL_BotRadioMessage (BotPointer, 3, "8", ""); // Negative!
+ BotPointer->f_console_timer = gpGlobals->time + RANDOM_FLOAT (0.8, 2.0);
+ radios++;
+ }
+ }
+ }
+ */
+ }
+ } // End check!
+ } // If (Player)
+ } // FOR Clients
+ return true;
+}
+
+// Is entity visible? (from Entity view)
+bool EntityIsVisible(edict_t* pEntity, const Vector& dest) {
+
+ //DebugOut("bot: EntityIsVisible()\n");
+ TraceResult tr;
+
+ // trace a line from bot's eyes to destination...
+ UTIL_TraceLine(pEntity->v.origin + pEntity->v.view_ofs, dest,
+ dont_ignore_monsters, pEntity->v.pContainingEntity, &tr);
+
+ // check if line of sight to object is not blocked (i.e. visible)
+ if (tr.flFraction >= 1.0f)
+ return true;
+
+ else
+ return false;
+}
+
+// Can see Edict?
+bool cBot::canSeeEntity(edict_t* pEntity) const
+{
+ if (pEntity == nullptr) return false;
+
+ TraceResult tr;
+ const Vector start = pEdict->v.origin + pEdict->v.view_ofs;
+ const Vector vDest = pEntity->v.origin;
+
+ // trace a line from bot's eyes to destination...
+ UTIL_TraceLine(start, vDest, ignore_monsters, pEdict->v.pContainingEntity, &tr);
+
+ // it hit anything
+ if (tr.flFraction < 1.0f) {
+ // if it hit the entity we wanted to see, then its ok!
+ if (tr.pHit == pEntity) return true;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Returns distance from this bot to a given nodeIndex. If the given NodeIndex is invalid, the distance returned is 0.
+ * @param nodeIndex
+ * @return
+ */
+float cBot::getDistanceTo(const int nodeIndex) {
+ const tNode* nodePtr = NodeMachine.getNode(nodeIndex);
+ if (nodePtr != nullptr) {
+ return getDistanceTo(nodePtr->origin);
+ }
+ rprint("getDistanceTo(int nodeIndex)", "The given nodeIndex was invalid, returning 9999 distance");
+ return 9999;
+}
+
+/**
+ * Returns distance from this bot position (pEdict->v.origin) to given Vector.
+ * @param vDest
+ * @return
+ */
+float cBot::getDistanceTo(const Vector& vDest) const
+{
+ return func_distance(pEdict->v.origin, vDest);
+}
+
+bool cBot::isUsingHostage(edict_t* pHostage) {
+ if (pHostage == nullptr) return false;
+
+ // checks if the current pEdict is already 'in use'
+ // note: time check only when we have an hostage pointer assigned
+ if (hostage1 == pHostage) {
+ rprint("isUsingHostage", "hostage1");
+ return true;
+ }
+
+ if (hostage2 == pHostage) {
+ rprint("isUsingHostage", "hostage2");
+ return true;
+ }
+
+ if (hostage3 == pHostage) {
+ rprint("isUsingHostage", "hostage3");
+ return true;
+ }
+
+ if (hostage4 == pHostage) {
+ rprint("isUsingHostage", "hostage4");
+ return true;
+ }
+
+ return false;
+}
+
+void cBot::forgetHostage(edict_t* pHostage) {
+ // these are the hostages we are rescueing (ie, they are following this bot)
+ if (hostage1 == pHostage) {
+ rprint("forgetHostage", "hostage1");
+ hostage1 = nullptr;
+ }
+ if (hostage2 == pHostage) {
+ rprint("forgetHostage", "hostage2");
+ hostage2 = nullptr;
+ }
+ if (hostage3 == pHostage) {
+ rprint("forgetHostage", "hostage3");
+ hostage3 = nullptr;
+ }
+ if (hostage4 == pHostage) {
+ rprint("forgetHostage", "hostage4");
+ hostage4 = nullptr;
+ }
+
+ // this is the hostage we have taken interest in
+ if (pBotHostage == pHostage) {
+ rprint("forgetHostage", "pBotHostage");
+ pBotHostage = nullptr;
+ }
+}
+
+int cBot::getAmountOfHostagesBeingRescued() const
+{
+ int count = 0;
+
+ if (hostage1 != nullptr) count++;
+ if (hostage2 != nullptr) count++;
+ if (hostage3 != nullptr) count++;
+ if (hostage4 != nullptr) count++;
+
+ return count;
+}
+
+// Will return true when the vector is visible.
+bool cBot::canSeeVector(const Vector& vDest, edict_t* pTargetEntity) const
+{
+ TraceResult tr;
+ const Vector start = pEdict->v.origin + pEdict->v.view_ofs;
+
+ // trace a line from bot's eyes to destination...
+ UTIL_TraceLine(start, vDest, ignore_monsters, pEdict->v.pContainingEntity, &tr);
+
+ // if trace is not blocked, the vector is visible
+ if (tr.flFraction >= 1.0f)
+ {
+ return true;
+ }
+
+ // if we have a target entity, check if we hit it
+ if (pTargetEntity != nullptr && tr.pHit == pTargetEntity)
+ {
+ return true; // we hit our target, so we can "see" it
+ }
+
+ return false; // something is blocking the view
+}
+
+// The coming 2 shield functions where originaly created by Whistler;
+// i got them from the JoeBot source though. But... in the end, thank you
+// Whistler!
+bool cBot::hasShield() const
+{
+ // Adapted from Wei Mingzhi's YAPB
+ return strncmp(STRING(pEdict->v.viewmodel), "models/shield/v_shield_", 23) == 0;
+}
+
+bool cBot::hasShieldDrawn() const
+{
+ // Adapted from Wei Mingzhi's YAPB
+ if (!hasShield())
+ return false;
+
+ return pEdict->v.weaponanim == 6 || pEdict->v.weaponanim == 7;
+}
+
+/*
+ BotThink()
+ This function is the very general/main/simplified thinking function of the bot.
+ Do NOT add/remove/change code here! If you want to give the bot information to
+ work with. Put it in UpdateStatus(). When the bot has to think about it, do it
+ int Think() and everything else (when all is set, how to 'do' it) in Act().
+ */
+void BotThink(cBot* pBot) {
+ // STEP 1: Update status
+ pBot->UpdateStatus();
+
+ // STEP 2: Think
+ pBot->Think();
+
+ // STEP 3: Act
+ pBot->Act();
+
+ // PASS THROUGH ENGINE
+
+ // float frameInterval = m_lastCommandTime - gpGlobals->time;
+ const float msecval = (gpGlobals->time - pBot->fLastRunPlayerMoveTime) * 1000.0f;
+ pBot->fLastRunPlayerMoveTime = gpGlobals->time;
+
+ constexpr double upMove = 0.0;
+ char msg[255];
+ snprintf(msg, sizeof(msg), "moveSpeed %f, strafeSpeed %f, msecVal %f", pBot->f_move_speed, pBot->f_strafe_speed, msecval);
+ pBot->rprint_trace("BotThink/pfnRunPlayerMove", msg);
+ g_engfuncs.pfnRunPlayerMove(pBot->pEdict, pBot->vecMoveAngles, pBot->f_move_speed, pBot->f_strafe_speed,
+ upMove, pBot->pEdict->v.button, 0, msecval);
+
+ constexpr float fUpdateInterval = 1.0f / 60.0f; // update at 60 fps
+ pBot->fUpdateTime = gpGlobals->time + fUpdateInterval;
+}
+
+// 17/07/04
+// log important variables of the bot (it will be called from dll.cpp once per active bot)
+// they are logged into reallog.txt file
+
+void cBot::Dump() {
+ char buffer[181];
+ const int iCurrentNode =
+ NodeMachine.getClosestNode(pEdict->v.origin, (NODE_ZONE * 2), pEdict);
+
+ snprintf(buffer, 180,
+ "%s (#%d %s): timers, now= %.0f, c4_time=%.0f, camp_time=%.0f, wait_time=%.0f, cover_time=%.0f, wander=%.0f, MoveToNodeTime=%.0f\n",
+ name, iBotIndex, (iTeam == 1) ? "T" : "CT", gpGlobals->time,
+ f_c4_time, f_camp_time, f_wait_time, f_cover_time, fWanderTime, fMoveToNodeTime);
+ rblog(buffer);
+ snprintf(buffer, 180, " GoalNode=%d, CurrentNode=%d, iPathFlags=",
+ iGoalNode, iCurrentNode);
+ switch (iPathFlags) {
+ case PATH_NONE:
+ std::strncat(buffer, "PATH_NONE ", 180);
+ break;
+ case PATH_DANGER:
+ std::strncat(buffer, "PATH_DANGER ", 180);
+ break;
+ case PATH_CONTACT:
+ std::strncat(buffer, "PATH_CONTACT ", 180);
+ break;
+ case PATH_CAMP:
+ std::strncat(buffer, "PATH_CAMP ", 180);
+ break;
+ default:
+ std::strncat(buffer, "???", 180);
+ }
+ std::strncat(buffer, "\n", 180);
+ rblog(buffer);
+ if (iGoalNode >= 0)
+ NodeMachine.dump_path(iBotIndex, pathIndex);
+}
+
+/**
+ * Will begin walk the path by setting pathNodeIndex to 0, which is a valid nr so that
+ * isWalkingPath returns true.
+ */
+void cBot::beginWalkingPath() {
+ this->pathIndex = 0;
+}
+
+bool cBot::hasHostageToRescue() const
+{
+ return pBotHostage != nullptr;
+}
+
+bool cBot::canSeeHostageToRescue() const
+{
+ return canSeeEntity(pBotHostage);
+}
+
+void cBot::clearHostageToRescueTarget() {
+ rprint_trace("clearHostageToRescueTarget", "clearing pBotHostage pointer");
+ this->pBotHostage = nullptr;
+}
+
+// Finds a free hostage pointer and assigns it.
+void cBot::rememberHostageIsFollowingMe(edict_t* pHostage) {
+ if (pHostage == nullptr) {
+ rprint_trace("rememberHostageIsFollowingMe", "ERROR assigning NULL pHostage pointer!?");
+ }
+ if (hostage1 == nullptr) {
+ rprint_trace("rememberHostageIsFollowingMe", "hostage1 slot is free.");
+ hostage1 = pHostage;
+ }
+ else if (hostage2 == nullptr) {
+ rprint_trace("rememberHostageIsFollowingMe", "hostage2 slot is free.");
+ hostage2 = pHostage;
+ }
+ else if (hostage3 == nullptr) {
+ rprint_trace("rememberHostageIsFollowingMe", "hostage3 slot is free.");
+ hostage3 = pHostage;
+ }
+ else if (hostage4 == nullptr) {
+ rprint_trace("rememberHostageIsFollowingMe", "hostage4 slot is free.");
+ hostage4 = pHostage;
+ }
+}
+
+void cBot::checkIfHostagesAreRescued() {
+ if (isHostageRescued(this, hostage1)) forgetHostage(hostage1);
+ if (isHostageRescued(this, hostage2)) forgetHostage(hostage2);
+ if (isHostageRescued(this, hostage3)) forgetHostage(hostage3);
+ if (isHostageRescued(this, hostage4)) forgetHostage(hostage4);
+}
+
+bool cBot::isOnSameTeamAs(const cBot* pBot) const
+{
+ if (pBot == nullptr) return false;
+ return pBot->iTeam == this->iTeam;
+}
+
+bool cBot::wantsToBuyStuff() const
+{
+ return buy_secondary == true ||
+ buy_primary == true ||
+ buy_ammo_primary == true ||
+ buy_ammo_secondary == true ||
+ buy_armor == true ||
+ buy_defusekit == true ||
+ buy_grenade == true ||
+ buy_flashbang > 0;
+}
+
+bool cBot::isUsingConsole() const
+{
+ return console_nr > 0;
+}
+
+bool cBot::shouldBeAbleToMove() const
+{
+ return !isDead() &&
+ !isFreezeTime() &&
+ !shouldCamp() &&
+ !shouldWait() &&
+ !shouldActWithC4();
+ // !isDucking() &&
+ // !isJumping();
+}
+
+edict_t* cBot::getEntityBetweenMeAndCurrentPathNodeToHeadFor() const
+{
+ TraceResult tr;
+ const Vector vOrigin = pEdict->v.origin;
+
+ const tNode* node = NodeMachine.getNode(getCurrentPathNodeToHeadFor());
+
+ //Using TraceHull to detect de_aztec bridge and other entities.
+ //DONT_IGNORE_MONSTERS, we reached it only when there are no other bots standing in our way!
+ //UTIL_TraceHull(vOrigin, vNode, dont_ignore_monsters, point_hull, pBot->pEdict, &tr);
+ //UTIL_TraceHull(vOrigin, vNode, dont_ignore_monsters, human_hull, pBot->pEdict, &tr);
+ UTIL_TraceHull(vOrigin, node->origin, dont_ignore_monsters, head_hull, pEdict, &tr);
+
+ // if nothing hit (else a wall is in between and we don't care about that):
+ if (tr.flFraction < 1.0f) {
+ if (tr.pHit) {
+ return tr.pHit;
+ }
+ }
+
+ return nullptr;
+}
+
+/**
+ * Get distance to the next node we're heading for
+ * @return
+ */
+float cBot::getDistanceToNextNode() const
+{
+ const tNode* node = NodeMachine.getNode(getCurrentPathNodeToHeadFor());
+ if (node) {
+ return getDistanceTo(node->origin);
+ }
+ return MAP_MAX_SIZE;
+}
+
+void cBot::setBodyToNode(const int nodeIndex) {
+ const tNode* node = NodeMachine.getNode(nodeIndex);
+ if (node) {
+ vBody = node->origin;
+ }
+}
+
+void cBot::lookAtNode(const int nodeIndex) {
+ const tNode* node = NodeMachine.getNode(nodeIndex);
+ if (node) {
+ vHead = node->origin;
+ }
+}
+
+/**
+ * Sets timer to allow movement to node, when timer expires we will think about severing the connection
+ * we used.
+ * @param timeInSeconds
+ */
+void cBot::setTimeToMoveToNode(const float timeInSeconds) {
+ char msg[255];
+ const float endTime = gpGlobals->time + timeInSeconds;
+ snprintf(msg, sizeof(msg), "Set to %f so results into end time of %f", timeInSeconds, endTime);
+ rprint_trace("setTimeToMoveToNode", msg);
+
+ this->nodeTimeIncreasedAmount = 0;
+ this->fMoveToNodeTime = endTime;
+}
+
+/**
+ * Whatever was set, increase the time given in function param. This expands the time a bit.
+ * @param timeInSeconds
+ */
+void cBot::increaseTimeToMoveToNode(const float timeInSeconds) {
+ if (nodeTimeIncreasedAmount < 2) {
+ nodeTimeIncreasedAmount++;
+ this->fMoveToNodeTime += timeInSeconds;
+ const float timeToMoveToNodeRemaining = getMoveToNodeTimeRemaining();
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "increaseTimeToMoveToNode with %f for the %d time, making time to move to node remaining %f.",
+ timeInSeconds, nodeTimeIncreasedAmount, timeToMoveToNodeRemaining);
+ rprint_trace("increaseTimeToMoveToNode", msg);
+ }
+ else {
+ rprint_trace("increaseTimeToMoveToNode", "Refused to increase time");
+ }
+}
+
+float cBot::getMoveToNodeTimeRemaining() const
+{
+ return fMoveToNodeTime - gpGlobals->time;
+}
+
+bool cBot::shouldCamp() const
+{
+ return f_camp_time > gpGlobals->time;
+}
+
+bool cBot::shouldWait() const
+{
+ return f_wait_time > gpGlobals->time;
+}
+
+void cBot::setTimeToWait(const float timeInSeconds)
+{
+ this->f_wait_time = gpGlobals->time + timeInSeconds;
+}
+
+bool cBot::shouldBeAbleToInteractWithButton() const
+{
+ return fButtonTime < gpGlobals->time;
+}
+
+bool cBot::hasButtonToInteractWith() const
+{
+ return pButtonEdict != nullptr;
+}
+
+bool cBot::hasCurrentNode() const
+{
+ return iCloseNode > -1;
+}
+
+/**
+ * Shorthand method for creating path with flags PATH_NONE.
+ * @param destinationNode
+ * @return
+ */
+bool cBot::createPath(const int destinationNode) {
+ return createPath(destinationNode, PATH_NONE);
+}
+
+/**
+ * Attempts to create a path from current node to destination. Returns true on success, false on failure.
+ * @param destinationNode
+ * @param flags
+ * @return
+ */
+bool cBot::createPath(const int destinationNode, const int flags) {
+ if (destinationNode < 0 || destinationNode >= MAX_NODES) {
+ rprint("createPath()", "Unable to create path because destination node provided is < 0 or > MAX_NODES");
+ return false;
+ }
+
+ const int currentNode = getCurrentNode();
+ if (currentNode < 0) {
+ rprint("createPath()", "Unable to create path to destination because I am not close to a start node");
+ return false;
+ }
+
+ forgetPath();
+
+ char msg[255] = {};
+ snprintf(msg, sizeof(msg), "Creating path from currentNode [%d] to destination node [%d]", currentNode, destinationNode);
+ rprint("createPath()", msg);
+
+ return NodeMachine.createPath(currentNode, destinationNode, iBotIndex, this, flags);
+}
+
+void cBot::doDuck() {
+ UTIL_BotPressKey(this, IN_DUCK);
+ this->f_hold_duck = gpGlobals->time + 0.5f;
+
+ this->increaseTimeToMoveToNode(0.5f);
+}
+
+bool cBot::isDucking() {
+ const bool b = keyPressed(IN_DUCK) || this->f_hold_duck > gpGlobals->time;
+ if (b) {
+ rprint_trace("isDucking", "Yes I am ducking");
+ }
+ return b;
+}
+
+bool cBot::isWalking() {
+ const bool b = !keyPressed(IN_RUN) || this->f_walk_time > gpGlobals->time;
+ if (b) {
+ rprint_trace("isWalking", "Yes I am walking");
+ }
+ return b;
+}
+
+void cBot::doJump(const Vector& vector) {
+ rprint_trace("doJump", "With vector");
+ // stay focussed with body and head to this vector
+ this->vHead = vector;
+ this->vBody = vector;
+
+ doJump();
+}
+
+void cBot::doJump() {
+ rprint_trace("doJump", "no vector");
+ UTIL_BotPressKey(this, IN_JUMP);
+ this->f_jump_time = gpGlobals->time + 0.75f;
+
+ // duck like this, because doDuck increases node time *again*, so no
+ UTIL_BotPressKey(this, IN_DUCK); // DUCK jump by default
+ this->f_hold_duck = gpGlobals->time + 0.5f;
+
+ this->increaseTimeToMoveToNode(0.75f);
+}
+
+bool cBot::isJumping() {
+ const bool b = keyPressed(IN_JUMP) || this->f_jump_time > gpGlobals->time;
+ if (b) {
+ rprint_trace("isJumping", "Yes I am jumping");
+ }
+ return b;
+}
+
+float cBot::DetermineStrafe(const bool bHitForwardLeft, const bool bHitForwardRight, const bool bHitLeft, const bool bHitRight)
+{
+ // Prioritize avoiding diagonal obstacles
+ if (!bHitForwardLeft && bHitForwardRight) {
+ rprint_trace("CheckAround", "Strafing left to avoid forward-right obstacle.");
+ return -f_max_speed;
+ }
+
+ if (bHitForwardLeft && !bHitForwardRight) {
+ rprint_trace("CheckAround", "Strafing right to avoid forward-left obstacle.");
+ return f_max_speed;
+ }
+
+ // If diagonals are clear, check for side obstacles
+ if (!bHitLeft && bHitRight) {
+ rprint_trace("CheckAround", "Strafing left to avoid right obstacle.");
+ return -f_max_speed;
+ }
+
+ if (bHitLeft && !bHitRight) {
+ rprint_trace("CheckAround", "Strafing right to avoid left obstacle.");
+ return f_max_speed;
+ }
+
+ rprint_trace("CheckAround", "No strafing needed or path is blocked on both sides.");
+ return 0.0f;
+}
+
+// Experimental DuckJump added for the NodeMachine [APG]RoboCop[CL]
+//
+void cBot::doDuckJump(const Vector& vector) {
+ rprint_trace("doDuckJump", "With vector");
+ // stay focussed with body and head to this vector
+ this->vHead = vector;
+ this->vBody = vector;
+
+ doDuckJump();
+}
+
+void cBot::doDuckJump() {
+ rprint_trace("doDuckJump", "no vector");
+ UTIL_BotPressKey(this, IN_DUCK);
+ this->f_hold_duck = gpGlobals->time + 0.75f;
+
+ UTIL_BotPressKey(this, IN_JUMP);
+ this->f_jump_time = gpGlobals->time + 0.75f;
+
+ this->increaseTimeToMoveToNode(0.75f);
+}
+
+// Bots require both the combination of the (IN_DUCK) and (IN_JUMP) key to be pressed
+// in order to properly duck jump.
+bool cBot::isDuckJumping() {
+ const bool b = keyPressed(IN_JUMP) && keyPressed(IN_DUCK) ||
+ this->f_hold_duck > gpGlobals->time && this->f_jump_time > gpGlobals->time;
+ if (b) {
+ rprint_trace("isDuckJumping", "Yes I am DuckJumping");
+ }
+ return b;
+}
+
+bool cBot::isStuck() const
+{
+ if (distanceMoved < 1.0f && f_move_speed > 0.0f) {
+ return true;
+ }
+ return false;
+}
+
+// $Log: bot.cpp,v $
+// Revision 1.21 2004/09/07 18:23:02 eric
+// - bumped version to 3061
+// - adding Frashman code to buy the weapon as selected by Josh's code
+// - Realbot is really the result of multiple people :-)
+//
+// Revision 1.20 2004/09/07 15:44:34 eric
+// - bumped build nr to 3060
+// - minor changes in add2 (to add nodes for Bsp2Rbn utilities)
+// - if compiled with USE_EVY_ADD, then the add2() function is used when adding
+// nodes based on human players instead of add()
+// - else, it now compiles mostly without warnings :-)
+//
+// Revision 1.19 2004/08/07 18:42:56 eric
+// - bumped version to 3058
+// - added a cNodeMachine::add2 which should do the same job as ::add
+// but it seems to work better. ::add2 is used by Bsp2Rbn only for now.
+// - added the display of node flags (water, ladder, jump) next to the
+// node position in 'debug nodes draw'
+// - suppress the debugging information which displayed the hit entity
+// while establishing neighbourhood
+//
+// Revision 1.18 2004/07/30 15:02:29 eric
+// - jumped to version 3057
+// - improved readibility (wapen_tabel -> weapons_table) :-P
+// - all Josh Borke modifications to the buying stuff:
+// * using a switch() instead of several if
+// * better buying code for shield and primary weapons
+// * new command 'debug pistols 0/1'
+//
+// Revision 1.16 2004/07/17 21:32:01 eric
+// - bumped version to 3055
+// - handling of es_ and as_ maps with new goals
+// - added two debug commands:
+// realbot debug goals
+// realbot debug bots
+// - added two nodes commands (for dedicated servers mainly)
+// realbot nodes connect n1 n2
+// realbot nodes disconnect n1 n2
+// - slight modification in goal scoring (only reduced score when two bots of
+// the SAME team select the same goal)
+//
+// Revision 1.15 2004/07/03 15:58:54 eric
+// nova test comment for erics account
+//
+// Revision 1.14 2004/07/02 16:43:35 stefan
+// - upped to build 3051
+// - changed log() into rblog()
+// - removed BOT.CFG code that interpets old RB V1.0 commands
+// - neater respons of the RealBot console
+// - more help from RealBot console (ie, type realbot server broadcast ... with no arguments it will tell you what you can do with this, etc)
+// - removed message "bot personality loaded from file"
+// - in overal; some cleaning done, no extra features added
+//
+// Revision 1.13 2004/07/01 18:09:46 stefan
+// - fixed skill 10 bots not causing memory bugger on re-adding (respawning)
+// - added extra check for respawning bots so auto-add function cannot crash
+// - fixed 2 nitpicks pointed out on the forums
+//
+// Revision 1.12 2004/06/25 07:39:00 stefan
+// - upped to build 3050
+// - fixed reaction time (instant reaction time) bug
+// - added evy's goals, but they are not used yet
+// - fixed some radio responses here and there for swat behaviour.
+// - swat leader automaticly assigned again when one dies
+// - HINT: you can see any changes made by me, by looking at DD/MM/YY - Stefan (ie, 22/06/04 - Stefan, will let you find all changes i made that day)
+//
+// Revision 1.11 2004/06/23 08:24:14 stefan
+// - upped to build 3049
+// - added swat behaviour (team leader assignment, radio response change and leaders command team-mates) - THIS IS EXPERIMENTAL AND DOES NOT ALWAYS WORK AS I WANT IT TO.
+// - changed some conditions in nodemachine
+// - sorry evy, still not added your new goals ;) will do next time, i promise
+//
+// Revision 1.10 2004/06/20 10:24:13 stefan
+// - fixed another steep/stair thingy
+// - changed a bit of the aiming code
+//
+// Revision 1.9 2004/06/19 21:06:14 stefan
+// - changed distance check in nodemachine
+// - fixed some 'steep' bug in nodemachine
+//
+// Revision 1.8 2004/06/17 21:23:23 stefan
+// - fixes several connection problems with nodes. Going down from steep + crates (de_dust) PLUS going up/down from very steep slopes on as_oilrig.. 0wnage and thx to PMB and Evy
+// - fixed chat bug in CS 1.6, its still CS 1.5 & CS 1.6 compatible though
+//
+// Revision 1.7 2004/06/13 20:08:21 stefan
+// - 'bad score for goals' added
+// - bmp dump info (Thanks Evy)
+// - added 'realbot server players', so you can keep a server full at NR players at all times
+// - slightly adjusted goal selection code
+// - wander code disabled
+// - lots of debug info introduced, do not use this source for REAL USAGE!
+//
+// Revision 1.6 2004/06/01 15:30:57 stefan
+// *** empty log message ***
+//
+// Revision 1.5 2004/05/29 19:05:47 stefan
+// - upped to BUILD 3044
+// - removed several debug messages on screen
+// - changed default 'chatrate (max sentences)' to 3
+// - removed copyright notice, which is not valid due GPL license
+//
+// i know, nothing special :)
+//
+// Revision 1.4 2004/05/07 13:33:49 stefan
+// added more comments, more neat code now
+//
+// Revision 1.3 2004/04/18 18:32:36 stefan
+// - Restructured code a bit
+//
+// Revision 1.2 2004/04/18 17:39:19 stefan
+// - Upped to build 2043
+// - REALBOT_PRINT() works properly now
+// - Log() works properly now
+// - Clearing in dll.cpp of reallog.txt at dll init
+// - Logging works now, add REALBOT_PRINT() at every point you want to log something.
+//
\ No newline at end of file
diff --git a/bot.h b/bot.h
index b3a6ec9..63576f8 100644
--- a/bot.h
+++ b/bot.h
@@ -6,7 +6,7 @@
**
* DISCLAIMER
*
- * History, Information & Credits:
+ * History, Information & Credits:
* RealBot is based partially upon the HPB-Bot Template #3 by Botman
* Thanks to Ditlew (NNBot), Pierre Marie Baty (RACCBOT), Tub (RB AI PR1/2/3)
* Greg Slocum & Shivan (RB V1.0), Botman (HPB-Bot) and Aspirin (JOEBOT). And
@@ -18,9 +18,9 @@
*
* Pierre Marie Baty
* Count-Floyd
- *
+ *
* !! BOTS-UNITED FOREVER !!
- *
+ *
* This project is open-source, it is protected under the GPL license;
* By using this source-code you agree that you will ALWAYS release the
* source-code with your project.
@@ -46,99 +46,99 @@ typedef struct {
extern weapon_price_table weapons_table[32];
// BOT SPECIFIC / AUDIOABLE / VISUAL PROPERTIES
-#define BOT_HEARDISTANCE 1500
-#define BOT_HEARFIREDISTANCE 2500
+constexpr int BOT_HEARDISTANCE = 1500;
+constexpr int BOT_HEARFIREDISTANCE = 2500;
// define constants used to identify the MOD we are playing...
-#define VALVE_DLL 1 // Added "Half-Life DeathMatch"
-#define CSTRIKE_DLL 3 // Added "Counter-Strike"
+constexpr int VALVE_DLL = 1; // Added "Half-Life DeathMatch";
+constexpr int CSTRIKE_DLL = 3; // Added "Counter-Strike";
// max names in rb_names.txt
-#define MAX_BOT_NAMES 100
+constexpr int MAX_BOT_NAMES = 100;
// Define Join states for other mods
-#define JOIN_TEAM 1
-#define JOIN_CLASS 2
-#define JOIN_NONE 9999
+constexpr int JOIN_TEAM = 1;
+constexpr int JOIN_CLASS = 2;
+constexpr int JOIN_NONE = 9999;
// fix for steam (cs 1.6 bot will crash when FL_FAKECLIENT;
// this is fixed later again in STEAM, but leave it in anway).
-#define FL_THIRDPARTYBOT (1 << 27)
+constexpr int FL_THIRDPARTYBOT = (1 << 27);
// "Own predefined" item types (attached with buying code)
-#define CS_WEAPON_ARMOR_LIGHT 199
-#define CS_WEAPON_ARMOR_HEAVY 299
+constexpr int CS_WEAPON_ARMOR_LIGHT = 199;
+constexpr int CS_WEAPON_ARMOR_HEAVY = 299;
// damage tolerance
-#define CSTRIKE_MIN_DAMAGE 7
-#define CSTRIKE_MAX_DAMAGE 14
+constexpr int CSTRIKE_MIN_DAMAGE = 7;
+constexpr int CSTRIKE_MAX_DAMAGE = 14;
// The type of a weapon, not mod related. You can use these prefixed names
// for your functions
-#define SNIPER 10 // Sniper gun
-#define RIFLE 20 // Rifle
-#define HANDGUN 30 // Handgun
-#define ARMOR 40 // Armor
-#define PRIMARY 50 // Its a primary weapon (for CS Mods)
-#define SECONDARY 60 // Its a secondary weapon (for CS Mods)
-#define GRENADE 70 // Grenade (aka, HE, Flashbang, C4, etc)
-#define KNIFE 80 // Knife / Crowbar etc
-#define SHIELD 90 // Shield (CS 1.6)
-#define NONE 99 // No type
+constexpr int SNIPER = 10; // Sniper gun;
+constexpr int RIFLE = 20; // Rifle;
+constexpr int HANDGUN = 30; // Handgun;
+constexpr int ARMOR = 40; // Armor;
+constexpr int PRIMARY = 50; // Its a primary weapon (for CS Mods);
+constexpr int SECONDARY = 60; // Its a secondary weapon (for CS Mods)
+constexpr int GRENADE = 70; // Grenade (aka, HE, Flashbang, C4, etc);
+constexpr int KNIFE = 80; // Knife / Crowbar etc
+constexpr int SHIELD = 90; // Shield (CS 1.6)
+constexpr int NONE = 99; // No type
// Strafe
//#define STRAFE_LEFT 0
//#define STRAFE_RIGHT 1
// zooming
-#define ZOOM_NONE 0
-#define ZOOM_ONCE 1
-#define ZOOM_TWICE 2
+constexpr int ZOOM_NONE = 0;
+constexpr int ZOOM_ONCE = 1;
+constexpr int ZOOM_TWICE = 2;
// instant damage (from cbase.h)
-#define DMG_CRUSH (1 << 0) // crushed by falling or moving object
-#define DMG_BURN (1 << 3) // heat burned
-#define DMG_FREEZE (1 << 4) // frozen
-#define DMG_FALL (1 << 5) // fell too far
-#define DMG_SHOCK (1 << 8) // electric shock
-#define DMG_DROWN (1 << 14) // Drowning
-#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
-#define DMG_RADIATION (1 << 18) // radiation exposure
-#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
-#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
-#define DMG_SLOWBURN (1 << 21) // in an oven
-#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer
+constexpr int DMG_CRUSH = (1 << 0); // crushed by falling or moving object
+constexpr int DMG_BURN = (1 << 3); // heat burned
+constexpr int DMG_FREEZE = (1 << 4); // frozen
+constexpr int DMG_FALL = (1 << 5); // fell too far
+constexpr int DMG_SHOCK = (1 << 8); // electric shock
+constexpr int DMG_DROWN = (1 << 14); // Drowning
+constexpr int DMG_NERVEGAS = (1 << 16); // nerve toxins, very bad
+constexpr int DMG_RADIATION = (1 << 18); // radiation exposure
+constexpr int DMG_DROWNRECOVER = (1 << 19); // drowning recovery
+constexpr int DMG_ACID = (1 << 20); // toxic chemicals or acid burns
+constexpr int DMG_SLOWBURN = (1 << 21); // in an oven
+constexpr int DMG_SLOWFREEZE = (1 << 22); // in a subzero freezer;
// define some function prototypes...
-void FakeClientCommand(edict_t *pBot, char *arg1, char *arg2, char *arg3);
+void FakeClientCommand(edict_t* pBot, const char* arg1, const char* arg2, const char* arg3);
-#define LADDER_UNKNOWN 0
-#define LADDER_UP 1
-#define LADDER_DOWN 2
+constexpr int LADDER_UNKNOWN = 0;
+constexpr int LADDER_UP = 1;
+constexpr int LADDER_DOWN = 2;
-#define WANDER_LEFT 1
-#define WANDER_RIGHT 2
+constexpr int WANDER_LEFT = 1;
+constexpr int WANDER_RIGHT = 2;
-#define BOT_PITCH_SPEED 20
-#define BOT_YAW_SPEED 20
+constexpr int BOT_PITCH_SPEED = 30;
+constexpr int BOT_YAW_SPEED = 30;
-#define RESPAWN_NONE 0 // Added by Stefan
-#define RESPAWN_IDLE 1
-#define RESPAWN_NEED_TO_RESPAWN 2
-#define RESPAWN_IS_RESPAWNING 3
+constexpr int RESPAWN_NONE = 0; // Added by Stefan;
+constexpr int RESPAWN_IDLE = 1;
+constexpr int RESPAWN_NEED_TO_RESPAWN = 2;
+constexpr int RESPAWN_IS_RESPAWNING = 3;
// game start messages for CS...
-#define MSG_CS_IDLE 1
-#define MSG_CS_TEAM_SELECT 2
-#define MSG_CS_CT_SELECT 3
-#define MSG_CS_T_SELECT 4
+constexpr int MSG_CS_IDLE = 1;
+constexpr int MSG_CS_TEAM_SELECT = 2;
+constexpr int MSG_CS_CT_SELECT = 3;
+constexpr int MSG_CS_T_SELECT = 4;
-#define BOT_SKIN_LEN 32
-#define BOT_NAME_LEN 32
+constexpr int BOT_SKIN_LEN = 32;
+constexpr int BOT_NAME_LEN = 32;
-#define MAX_BOT_WHINE 100
+constexpr int MAX_BOT_WHINE = 100;
-#define REMEMBER_ENEMY_TIME 20 // remember for 20 seconds
+constexpr int REMEMBER_ENEMY_TIME = 20; // remember for 20 seconds
typedef struct {
int iId; // weapon ID
@@ -146,10 +146,10 @@ typedef struct {
int iAmmo1; // amount of ammo in primary reserve
int iAmmo2; // amount of ammo in secondary reserve
}
- bot_current_weapon_t;
+bot_current_weapon_t;
/*
- Bot is a class now
+ Bot is a class now
*/
class cBot {
@@ -159,13 +159,13 @@ class cBot {
int pathIndex; // Index on theWhich node we want to move to, derived from Path
// Hostages edict
- edict_t *pBotHostage; // the Hostage we will go after!
- edict_t *hostage1; // we do not
- edict_t *hostage2; // use
- edict_t *hostage3; // any array
- edict_t *hostage4; // here
+ edict_t* pBotHostage; // the Hostage we will go after!
+ edict_t* hostage1; // we do not
+ edict_t* hostage2; // use
+ edict_t* hostage3; // any array
+ edict_t* hostage4; // here
- edict_t *pEnemyEdict; // Enemy edict
+ edict_t* pEnemyEdict; // Enemy edict
float fMoveToNodeTime; // How long we should take to move to next node.
int nodeTimeIncreasedAmount; // how many times did we increase the time to reach node?
@@ -182,19 +182,19 @@ class cBot {
cBot();
// Hostage related
- bool isUsingHostage(edict_t *pHostage);
- void forgetHostage(edict_t *pHostage);
- void rememberHostageIsFollowingMe(edict_t *pHostage);
- void rememberWhichHostageToRescue(edict_t *pHostage);
+ bool isUsingHostage(edict_t* pHostage);
+ void forgetHostage(edict_t* pHostage);
+ void rememberHostageIsFollowingMe(edict_t* pHostage);
+ void rememberWhichHostageToRescue(edict_t* pHostage);
void clearHostageToRescueTarget();
- int getAmountOfHostagesBeingRescued();
- edict_t * findHostageToRescue(); // finds a hostage to rescue
- edict_t * getHostageToRescue(); // returns hostage state pointer
+ int getAmountOfHostagesBeingRescued() const;
+ edict_t* findHostageToRescue(); // finds a hostage to rescue
+ edict_t* getHostageToRescue() const; // returns hostage state pointer
bool isEscortingHostages(); // Does the bot has used any hostages yet?
void checkOfHostagesStillFollowMe();
- bool hasTimeToMoveToNode();
- bool isDefusing();
+ bool hasTimeToMoveToNode() const;
+ bool isDefusing() const;
// ------------------------
// TIMERS
@@ -307,24 +307,26 @@ class cBot {
// Remember stuck stuff
int iJumpTries;
int iDuckTries;
+ int iDuckJumpTries; // Experimental DuckJump added for this new node [APG]RoboCop[CL]
// ------------------------
// BOOLEANS
// ------------------------
- bool buy_primary;
- bool buy_secondary;
+ bool vip;
+ bool bWalkKnife;
bool buy_ammo_primary;
bool buy_ammo_secondary;
+ bool buy_primary;
+ bool buy_secondary;
bool buy_armor;
- bool buy_grenade;
- bool buy_smokegrenade; //31.08.04 Frashman added support for Smoke Grenade
- bool bIsUsed; // Bot is 'used'/'playing' (if set to true, the bot is active)
- bool bInitialize;
bool buy_defusekit;
- bool bWalkKnife; // likes to walk around with knife
- bool vip;
-
bool bFirstOutOfSight;
+ bool buy_grenade;
+ bool buy_smokegrenade;
+ bool bIssuedInitialRadio;
+
+ bool bInitialize; // Has the bot been initialized yet?
+ bool bIsUsed; // Is this bot slot used?
// ------------------------
// HUD
@@ -335,10 +337,12 @@ class cBot {
char chChatSentence[160];
// ------------------------
- //
- // ------------------------
-
- edict_t *pEdict; // Edict_t of the bot
+ // POINTERS
+ // ------------------------
+ edict_t* pBreakableEdict; // Breakable edict
+ edict_t* pButtonEdict; // button edict
+ edict_t* killer_edict; // Killer edict
+ edict_t* pEdict; // Edict_t of the bot
char name[BOT_NAME_LEN + 1];
char skin[BOT_SKIN_LEN + 1];
@@ -369,10 +373,6 @@ class cBot {
float f_bot_see_enemy_time;
float f_bot_find_enemy_time;
- edict_t *pButtonEdict; // button edict
-
- edict_t *killer_edict; // Killer edict
-
Vector vecMoveAngles; // Vector we move to
@@ -394,29 +394,29 @@ class cBot {
void CheckGear();
void ThinkAboutGoals(); // Think about goals
- bool TakeCover();
+ bool TakeCover() const;
- bool CarryWeapon(int iType);
+ bool CarryWeapon(int iType) const;
- int CarryWeaponType();
+ int CarryWeaponType() const;
- void setHeadAiming(Vector vTarget); // Aim at vector
+ void setHeadAiming(const Vector& vTarget); // Aim at vector
void AimAtEnemy();
void PickBestWeapon();
void FireWeapon();
- int ReturnTurnedAngle(float speed, float current, float ideal);
+ static vec_t ReturnTurnedAngle(float speed, float current, float ideal);
int FindEnemy();
float ReactionTime(int iSkill); // Reaction time based upon skill
void FindCover();
- bool canSeeVector(Vector vDest);
+ bool canSeeVector(const Vector& vDest, edict_t* pTargetEntity = nullptr) const;
- bool canSeeEntity(edict_t *pEntity);
+ bool canSeeEntity(edict_t* pEntity) const;
void InteractWithFriends();
@@ -427,40 +427,40 @@ class cBot {
// Set methods
int determineCurrentNode();
int determineCurrentNodeWithTwoAttempts();
- int determineCurrentNode(float range);
+ int determineCurrentNode(float range) const;
// Get methods
float getDistanceTo(int nodeIndex);
- float getDistanceTo(Vector vDest);
+ float getDistanceTo(const Vector& vDest) const;
// "is" Methods (booleans, statements, etc)
- bool isDead();
- bool isHeadingForGoalNode();
- bool isEnemyAlive(); // If enemy set, is it alive? (else returns false)
- bool isOnLadder(); // Bot on ladder or not?
+ bool isDead() const;
+ bool isHeadingForGoalNode() const;
+ bool isEnemyAlive() const; // If enemy set, is it alive? (else returns false)
+ bool isOnLadder() const; // Bot on ladder or not?
bool isSeeingEnemy(); // If enemy set, can we see it? (takes blinded by flashbang into account)
- bool isCounterTerrorist();
- bool isTerrorist();
+ bool isCounterTerrorist() const;
+ bool isTerrorist() const;
// "is" methods, related to weapons
- bool wantsToBuyStuff();
- bool isUsingConsole();
- bool isOwningWeapon(int weaponId);
- bool isHoldingWeapon(int weaponId);
- bool ownsFavoritePrimaryWeapon();
- bool ownsFavoriteSecondaryWeapon();
- bool hasFavoritePrimaryWeaponPreference();
- bool hasFavoriteSecondaryWeaponPreference();
- bool hasPrimaryWeaponEquiped();
- bool hasSecondaryWeaponEquiped();
- bool hasPrimaryWeapon(int weaponId);
- bool hasSecondaryWeapon(int weaponId);
- bool canAfford(int weaponId);
+ bool wantsToBuyStuff() const;
+ bool isUsingConsole() const;
+ bool isOwningWeapon(int weaponId) const;
+ bool isHoldingWeapon(int weaponId) const;
+ bool ownsFavoritePrimaryWeapon() const;
+ bool ownsFavoriteSecondaryWeapon() const;
+ bool hasFavoritePrimaryWeaponPreference() const;
+ bool hasFavoriteSecondaryWeaponPreference() const;
+ bool hasPrimaryWeaponEquiped() const;
+ bool hasSecondaryWeaponEquiped() const;
+ //bool hasPrimaryWeapon(int weaponId) const;
+ //bool hasSecondaryWeapon(int weaponId) const;
+ bool canAfford(int price) const; //price muddled with weaponId? [APG]RoboCop[CL]
// -------------------
// 20/06/04 - CS 1.6 shield functions
- bool hasShield();
- bool hasShieldDrawn();
+ bool hasShield() const;
+ bool hasShieldDrawn() const;
bool isHoldingGrenadeOrFlashbang() const;
bool isBlindedByFlashbang() const;
@@ -468,26 +468,24 @@ class cBot {
// void / action methods
void pickWeapon(int weaponId);
void performBuyActions(int weaponIdToBuy);
- void performBuyWeapon(const char *menuItem, const char *subMenuItem);
+ void performBuyWeapon(const char* menuItem, const char* subMenuItem);
// -------------------
void CheckAround(); // Check around body
-
// -------------------
- //
- bool hasEnemy();
- bool hasEnemy(edict_t * pEdict);
- edict_t * getEnemyEdict();
+ bool hasEnemy() const;
+ bool hasEnemy(const edict_t* pEntity) const;
+ edict_t* getEnemyEdict() const;
- bool hasGoal();
- bool hasGoalIndex();
- tGoal *getGoalData();
+ bool hasGoal() const;
+ bool hasGoalIndex() const;
+ tGoal* getGoalData() const;
bool shouldBeWandering();
- bool hasBomb();
+ bool hasBomb() const;
// ------------
- bool isWalkingPath();
+ bool isWalkingPath() const;
void beginWalkingPath();
void nextPathIndex(); // increases index so we know which node to walk on path
@@ -496,20 +494,18 @@ class cBot {
void forgetGoal();
void forgetPath();
void forgetEnemy();
- void setGoalNode(tGoal *goal);
+ void setGoalNode(tGoal* goal);
void setGoalNode(int nodeIndex);
void setGoalNode(int nodeIndex, int iGoalIndex);
int getCurrentNode(); // the current (closest) node we are at
- int getCurrentPathNodeToHeadFor(); // get Node from path
- int getPreviousPathNodeToHeadFor(); // get previous Node from path
- int getNextPathNode(); // get next Node from path
- int getPathIndex();
- int getPreviousPathIndex();
-
- int getGoalNode();
-
+ int getCurrentPathNodeToHeadFor() const; // get Node from path
+ int getPreviousPathNodeToHeadFor() const; // get previous Node from path
+ int getNextPathNode() const; // get next Node from path
+ int getPathIndex() const;
+ int getPreviousPathIndex() const;
+ int getGoalNode() const;
void setMoveSpeed(float value);
void setStrafeSpeed(float value, float time);
@@ -522,28 +518,28 @@ class cBot {
void NewRound(); // When bot enters new round
// Debug -------
- void rprint(const char *Function, const char *msg); // low
- void rprint_normal(const char *Function, const char *msg); // normal
- void rprint_trace(const char *Function, const char *msg); // trace
+ void rprint(const char* Function, const char* msg); // low
+ void rprint_normal(const char* Function, const char* msg); // normal
+ void rprint_trace(const char* Function, const char* msg); // trace
- void rprint(const char *msg);
- void rprint_normal(const char *msg);
- void rprint_trace(const char *msg);
+ void rprint(const char* msg);
+ void rprint_normal(const char* msg);
+ void rprint_trace(const char* msg);
void Dump();
- bool hasHostageToRescue();
+ bool hasHostageToRescue() const;
- bool canSeeHostageToRescue();
+ bool canSeeHostageToRescue() const;
void checkIfHostagesAreRescued();
- bool isOnSameTeamAs(cBot *pBot);
+ bool isOnSameTeamAs(const cBot* pBot) const;
- bool shouldBeAbleToMove();
+ bool shouldBeAbleToMove() const;
- edict_t *getEntityBetweenMeAndCurrentPathNodeToHeadFor();
+ edict_t* getEntityBetweenMeAndCurrentPathNodeToHeadFor() const;
- float getDistanceToNextNode();
+ float getDistanceToNextNode() const;
void setBodyToNode(int nodeIndex);
@@ -552,99 +548,144 @@ class cBot {
void setTimeToMoveToNode(float timeInSeconds);
void increaseTimeToMoveToNode(float timeInSeconds);
- float getMoveToNodeTimeRemaining();
+ float getMoveToNodeTimeRemaining() const;
bool shouldActWithC4() const;
int keyPressed(int key) const;
- bool shouldCamp();
- bool shouldWait();
+ bool shouldCamp() const;
+ bool shouldWait() const;
void setTimeToWait(float timeInSeconds);
- bool shouldBeAbleToInteractWithButton();
+ bool shouldBeAbleToInteractWithButton() const;
- bool hasButtonToInteractWith();
- bool hasCurrentNode();
+ bool hasButtonToInteractWith() const;
+ bool hasCurrentNode() const;
bool createPath(int destinationNode, int flags);
bool createPath(int destinationNode);
- void doJump(Vector &vector);
+ void doJump(const Vector& vector);
void doJump();
bool isJumping();
+ // Experimental DuckJump added for the NodeMachine [APG]RoboCop[CL]
+ void doDuckJump(const Vector& vector);
+ void doDuckJump();
+ bool isDuckJumping();
+
+ bool isStuck() const;
+
void doDuck();
bool isDucking();
+ bool isWalking();
bool isFreezeTime() const;
void rememberEnemyFound();
+private:
+ float DetermineStrafe(bool bHitForwardLeft, bool bHitForwardRight, bool bHitLeft, bool bHitRight);
};
// new UTIL.CPP functions...
-edict_t *UTIL_FindEntityInSphere(edict_t *pentStart,
- const Vector &vecCenter, float flRadius);
+edict_t* UTIL_FindEntityInSphere(edict_t* pentStart,
+ const Vector& vecCenter, float flRadius);
-edict_t *UTIL_FindEntityByString(edict_t *pentStart,
- const char *szKeyword,
- const char *szValue);
+edict_t* UTIL_FindEntityByString(edict_t* pentStart,
+ const char* szKeyword,
+ const char* szValue);
-edict_t *UTIL_FindEntityByClassname(edict_t *pentStart,
- const char *szName);
+edict_t* UTIL_FindEntityByClassname(edict_t* pentStart,
+ const char* szName);
-edict_t *UTIL_FindEntityByTargetname(edict_t *pentStart,
- const char *szName);
+edict_t* UTIL_FindEntityByTargetname(edict_t* pentStart,
+ const char* szName);
-void ClientPrint(edict_t *pEdict, int msg_dest, const char *msg_name);
+void ClientPrint(edict_t* pEdict, int msg_dest, const char* msg_name);
-void UTIL_SayText(const char *pText, edict_t *pEdict);
+void UTIL_SayText(const char* pText, edict_t* pEdict);
-void UTIL_HostSay(edict_t *pEntity, int teamonly, char *message);
+void UTIL_HostSay(edict_t* pEntity, int teamonly, char* message);
-int UTIL_GetTeam(edict_t *pEntity);
+int UTIL_GetTeam(edict_t* pEntity);
-int UTIL_GetClass(edict_t *pEntity);
+int UTIL_GetClass(edict_t* pEntity);
-bool IsAlive(edict_t *pEdict);
+bool IsAlive(edict_t* pEdict);
-bool FInViewCone(Vector *pOrigin, edict_t *pEdict);
+bool FInViewCone(Vector* pOrigin, edict_t* pEdict);
-bool FVisible(const Vector &vecOrigin, edict_t *pEdict);
+bool FVisible(const Vector& vecOrigin, edict_t* pEdict);
-Vector Center(edict_t *pEdict);
+Vector Center(edict_t* pEdict);
-Vector GetGunPosition(edict_t *pEdict);
+Vector GetGunPosition(edict_t* pEdict);
-Vector VecBModelOrigin(edict_t *pEdict);
+Vector VecBModelOrigin(edict_t* pEdict);
-void UTIL_ShowMenu(edict_t *pEdict, int slots, int displaytime, bool needmore, char *pText);
+void UTIL_ShowMenu(edict_t* pEdict, int slots, int displaytime, bool needmore, const char* pText);
-void UTIL_SelectItem(edict_t *pEdict, char *item_name);
+void UTIL_SelectItem(edict_t* pEdict, const char* item_name);
-void UTIL_BuildFileName(char *filename, char *arg1, char *arg2);
+void UTIL_BuildFileName(char* filename, const char* arg1, const char* arg2);
-void UTIL_BuildFileNameRB(char *subdir, char *filename);
+void UTIL_BuildFileNameRB(const char* subdir, char* filename);
-unsigned short FixedUnsigned16(float value, float scale);
+unsigned short fixed_unsigned16(float value, float scale); //redundant declaration? [APG]RoboCop[CL]
-short FixedSigned16(float value, float scale);
+short fixed_signed16(float value, float scale); //redundant declaration? [APG]RoboCop[CL]
-void HUD_DrawString(int r, int g, int b, char *msg, edict_t *edict);
+void HUD_DrawString(int r, int g, int b, const char* msg, edict_t* edict);
-void UTIL_FixAngles(Vector *Angles);
+void UTIL_FixAngles(Vector* Angles);
-void UTIL_SayTextBot(const char *pText, cBot *pBot);
+void UTIL_SayTextBot(const char* pText, cBot* pBot);
// combat.h
// Bot specific
-int UTIL_GetBotIndex(edict_t *pEdict);
+int UTIL_GetBotIndex(edict_t* pEdict);
+
+cBot* UTIL_GetBotPointer(edict_t* pEdict);
+
+// IniParser.ini
+void INI_Section(char input[80], char section[30]);
+void INI_Word(char input[80], char word[25]);
+int INI_WordType(char word[25], int section);
+void INI_Sentence(FILE* f, char result[80]);
-cBot *UTIL_GetBotPointer(edict_t *pEdict);
+int INI_SectionType(char section[30], int last);
+int INI_SectionType_BUYTABLE(char section[30], int last);
+int INI_WordValueINT(char result[80]);
+
+float INI_WordValueFLOAT(char result[80]);
+
+void INI_WordValueCHAR(char result[80], char value[80]);
// dll.cpp
+void UpdateClientData(const edict_s* ent, int sendweapons, clientdata_s* cd);
+void ProcessBotCfgFile();
bool BotRadioAction();
+void GameDLLInit();
+
+#ifdef _WIN32
+int WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
+#endif
+
+int ClientConnect(edict_t* pEntity, const char* pszName, const char* pszAddress, char szRejectReason[128]);
+
+void ClientDisconnect(edict_t* pEntity);
+void ConsoleThink(cBot* pBot);
+void ClientPutInServer(edict_t* pEntity);
+void StartFrame();
+void RealBot_ServerCommand();
+
+int Spawn(edict_t* pent);
+int Spawn_Post(edict_t* pent);
+
+// util.cpp
+void UTIL_BotSprayLogo(edict_t* pEntity, const char* logo_name);
#endif // BOT_H
diff --git a/bot_buycode.cpp b/bot_buycode.cpp
index 4f2934c..6038bb3 100644
--- a/bot_buycode.cpp
+++ b/bot_buycode.cpp
@@ -1,3 +1,5 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check it.
+// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
/**
* RealBot : Artificial Intelligence
* Version : Work In Progress
@@ -27,7 +29,9 @@
*
**/
-#include
+#include
+#include
+#include
#include
#include
#include
@@ -52,17 +56,17 @@ void LoadDefaultWeaponTable() { /* REMOVED */
}
// Returns price of a weapon, checking on WEAPON_ID (of CS)
-int PriceWeapon(int weapon_id) {
+int PriceWeapon(const int weapon_id) {
return weapons_table[weapons_table[weapon_id].iIdIndex].price;
}
// Returns the ID in the list, checking on WEAPON_ID (of CS)
-int ListIdWeapon(int weapon_id) {
+int ListIdWeapon(const int weapon_id) {
return weapons_table[weapon_id].iIdIndex;
}
// The bot will be buying this weapon
-void BotPrepareConsoleCommandsToBuyWeapon(cBot *pBot, const char *arg1, const char *arg2) {
+void BotPrepareConsoleCommandsToBuyWeapon(cBot* pBot, const char* arg1, const char* arg2) {
// To be sure the console will only change when we MAY change.
// The values will only be changed when console_nr is 0
if (Game.getRoundStartedTime() + 4 < gpGlobals->time)
@@ -70,12 +74,16 @@ void BotPrepareConsoleCommandsToBuyWeapon(cBot *pBot, const char *arg1, const ch
if (pBot->console_nr == 0) {
// set up first command and argument
- strcpy(pBot->arg1, "buy");
- strcpy(pBot->arg2, arg1);
+ snprintf(pBot->arg1, sizeof(pBot->arg1), "buy");
+ snprintf(pBot->arg2, sizeof(pBot->arg2), "%s", arg1);
// add argument
- if (arg2 != NULL)
- strcpy(pBot->arg3, arg2);
+ if (arg2 != nullptr) {
+ snprintf(pBot->arg3, sizeof(pBot->arg3), "%s", arg2);
+ }
+ else {
+ pBot->arg3[0] = '\0';
+ }
pBot->console_nr = 1; // start console command sequence
}
@@ -88,69 +96,35 @@ void BotPrepareConsoleCommandsToBuyWeapon(cBot *pBot, const char *arg1, const ch
* @param team
* @return
*/
-bool GoodWeaponForTeam(int weapon, int team) {
+bool GoodWeaponForTeam(const int weapon, const int team) {
// Mod CS:
if (mod_id == CSTRIKE_DLL) {
-
- // When not playing Counter-Strike 1.6, these weapons are automaticly wrong for all teams.
- if (counterstrike == 0)
- if (weapon == CS_WEAPON_GALIL || weapon == CS_WEAPON_FAMAS
- || weapon == CS_WEAPON_SHIELD)
+ // When not playing Counter-Strike 1.6, these weapons are automatically wrong for all teams.
+ if (counterstrike == 0) {
+ if (weapon == CS_WEAPON_GALIL || weapon == CS_WEAPON_FAMAS || weapon == CS_WEAPON_SHIELD) {
return false;
+ }
+ }
+
+ // Define team-specific restricted weapons
+ static const std::unordered_set ct_restricted = {
+ CS_WEAPON_SG552, CS_WEAPON_AK47, CS_WEAPON_DEAGLE, CS_WEAPON_MP5NAVY,
+ CS_WEAPON_GALIL, CS_WEAPON_P90, CS_WEAPON_G3SG1
+ };
- // Check the real thing
- if (team == 2) // Counter-Terrorist
- {
- // 30/07/04 by Josh
- // Use a switch instead of multiple if
- switch (weapon) {
- case CS_WEAPON_SG552:
- return false;
- break;
- case CS_WEAPON_AK47:
- return false;
- break;
- case CS_WEAPON_ELITE:
- return false;
- break;
- case CS_WEAPON_MAC10:
- return false;
- break;
- case CS_WEAPON_GALIL:
- return false;
- break;
- // 30.8.04 added by frashman
- case CS_WEAPON_G3SG1:
- return false;
- break;
+ static const std::unordered_set t_restricted = {
+ CS_WEAPON_AUG, CS_WEAPON_DEAGLE, CS_WEAPON_M4A1, CS_WEAPON_MP5NAVY,
+ CS_WEAPON_FAMAS, CS_WEAPON_P90, CS_WEAPON_SG550, CS_DEFUSEKIT
+ };
+
+ if (team == 2) { // Counter-Terrorist
+ if (ct_restricted.count(weapon)) {
+ return false;
}
- } else {
- switch (weapon) {
- case CS_WEAPON_AUG:
- return false;
- break;
- case CS_WEAPON_FIVESEVEN:
- return false;
- break;
- case CS_WEAPON_M4A1:
- return false;
- break;
- case CS_WEAPON_TMP:
- return false;
- break;
- case CS_WEAPON_FAMAS:
- return false;
- break;
- case CS_WEAPON_SHIELD:
- return false;
- break;
- //30.8.04 added by Frashman
- case CS_WEAPON_SG550:
- return false;
- break;
- case CS_DEFUSEKIT:
- return false;
- break;
+ }
+ else { // Terrorist
+ if (t_restricted.count(weapon)) {
+ return false;
}
}
}
@@ -160,273 +134,195 @@ bool GoodWeaponForTeam(int weapon, int team) {
/*
BotDecideWhatToBuy()
-
+
In this function the bot will choose what weapon to buy from the table.
*/
-void BotDecideWhatToBuy(cBot *pBot) {
- /**
- * Stefan 02/09/2018
- *
- * This function is called multiple frames. And it basically checks boolean flags (buy_*) method, if true
- * then a weapon to buy is choosen. Once choosen it is bought. The flag which was 'true' now became 'false'.
- *
- * Then the next frame, the boolean flag before will become 'false' and thus another if block is executed.
- *
- * Effectively doing:
- * - buy primary weapon first
- * - then secondary
- * - ammo for primary
- * - ammo for secondary
- * - armor
- * - defuse kit
- * - etc.
- *
- * the order of if statements is leading
- *
- * In other words, it needs refactoring...
- *
- */
- int money = pBot->bot_money; // Money
- int team = pBot->iTeam; // Team
-
+int BotBuyPrimaryWeapon(cBot *pBot) {
+ const int money = pBot->bot_money;
+ const int team = pBot->iTeam;
int buy_weapon = -1;
- // Buy a primary weapon, think of the best choice
- if (pBot->buy_primary) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_primary");
- // Buy primary
-
- // Personality related:
- // Check if we can buy our favorite weapon
- if (pBot->hasFavoritePrimaryWeaponPreference()) {
- pBot->rprint("BotDecideWhatToBuy()", "I have a primary weapon preference");
-
- if (!pBot->ownsFavoritePrimaryWeapon()) {
- pBot->rprint("BotDecideWhatToBuy()", "I do not own my primary weapon preference");
-
- if (GoodWeaponForTeam(pBot->ipFavoPriWeapon, pBot->iTeam)) { // can we buy it for this team?
-
- if (pBot->canAfford(PriceWeapon(pBot->ipFavoPriWeapon))) { // can we afford it?
- // Buy favorite weapon!
- pBot->rprint("BotDecideWhatToBuy()", "Can buy my favorite primary weapon, doing it");
- buy_weapon = pBot->ipFavoPriWeapon;
- } else {
- pBot->rprint("BotDecideWhatToBuy()", "Can't afford my favorite primary weapon.");
-
- // bot personality: if we want to save money for our favorite weapon, then set other values to false
- if (RANDOM_LONG(0, 100) < pBot->ipSaveForWeapon) { // 31.08.04 Frashman forgotten brace
- pBot->rprint("Decided to save extra money");
- pBot->buy_primary = false;
- pBot->buy_secondary = false; // don't buy a secondary
- return; // get out of function, don't buy anything
- }
- }
+ // Personality related:
+ // Check if we can buy our favorite weapon
+ if (pBot->hasFavoritePrimaryWeaponPreference()) {
+ if (!pBot->ownsFavoritePrimaryWeapon()) {
+ if (GoodWeaponForTeam(pBot->ipFavoPriWeapon, pBot->iTeam)) { // can we buy it for this team?
+ if (pBot->canAfford(PriceWeapon(pBot->ipFavoPriWeapon))) { // can we afford it?
+ return pBot->ipFavoPriWeapon;
+ }
+ // bot personality: if we want to save money for our favorite weapon, then set other values to false
+ if (RANDOM_LONG(0, 100) < pBot->ipSaveForWeapon) {
+ pBot->rprint("Decided to save extra money");
+ pBot->buy_secondary = false; // don't buy a secondary
+ return -2; // Special value to indicate "stop buying"
}
- } else {
- pBot->rprint("BotDecideWhatToBuy()", "I already have my favorite primary weapon");
- // already have my favorite weapon
- pBot->buy_primary = false; // do not buy a primary weapon
- return;
}
}
+ else {
+ // already have my favorite weapon
+ return -2; // Stop buying
+ }
+ }
- // not decided what to buy yet
- if (buy_weapon < 0) {
- pBot->rprint("BotDecideWhatToBuy()", "I have no primary weapon preference, deciding what to buy.");
-
- // Find weapon we can buy in the list of weapons
- for (int i = 0; i < MAX_WEAPONS; i++) {
+ // Find weapon we can buy in the list of weapons
+ for (const weapon_price_table& i : weapons_table) {
+ if (UTIL_GiveWeaponType(i.iId) != PRIMARY && UTIL_GiveWeaponType(i.iId) != SHIELD)
+ continue;
- // 31.08.04 Frashman Filter Out all except PRIMARY and SHIELD
- // SHIELD is used as primary weapon
+ if (!GoodWeaponForTeam(i.iId, team))
+ continue;
- if ((UTIL_GiveWeaponType(weapons_table[i].iId) != PRIMARY)
- && (UTIL_GiveWeaponType(weapons_table[i].iId) != SHIELD))
- continue;
-
- // must be a weapon that the team can buy (CT/T weapon)
- if (!GoodWeaponForTeam(weapons_table[i].iId, team))
+ if (i.price <= money) {
+ if (pBot->iPrimaryWeapon > -1) {
+ if (weapons_table[ListIdWeapon(pBot->iPrimaryWeapon)].priority >= i.priority)
continue;
+ }
- // can afford it
- if (weapons_table[i].price <= money) {
-
- // owns a primary weapon
- if (pBot->iPrimaryWeapon > -1) {
- // and the primary weapon has a higher priority than the other primary weapon
- if (weapons_table[ListIdWeapon(pBot->iPrimaryWeapon)].priority >= weapons_table[i].priority)
- continue;
- }
-
- // nothing to buy yet, so chose this one
- if (buy_weapon == -1) {
- buy_weapon = weapons_table[i].iId;
- } else {
- // randomly overrule it based on priority. The higher priority the more chance
- // it will be bought.
- if (RANDOM_LONG(0, 100) < weapons_table[i].priority) {
- buy_weapon = weapons_table[i].iId; // randomly buy a different weapon
- }
- }
+ if (buy_weapon == -1) {
+ buy_weapon = i.iId;
+ }
+ else {
+ if (RANDOM_LONG(0, 100) < i.priority) {
+ buy_weapon = i.iId;
}
}
}
+ }
- pBot->buy_primary = false;
-
- // has decided which weapon to buy
- if (buy_weapon != -1) {
- pBot->rprint("BotDecideWhatToBuy()", "Found a primary weapon to buy");
+ return buy_weapon;
+}
- // depending on amount of money we have left buy *also* secondary weapon
- int iMoneyLeft = money - PriceWeapon(buy_weapon);
+int BotBuySecondaryWeapon(cBot *pBot) {
+ const int money = pBot->bot_money;
+ const int team = pBot->iTeam;
+ int buy_weapon = -1;
- // TODO: this should be dependant on something else... not only money
- // 01.09.04 Frashman if buyed a Shield, try to buy a good Pistol
- if (iMoneyLeft >= 600)
- if ((RANDOM_LONG(0, 100) < 15)
- || (pBot->iPrimaryWeapon == CS_WEAPON_SHIELD))
- pBot->buy_secondary = true;
- }
- } else if (pBot->buy_secondary) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_secondary");
- // Buy secondary
-
- // Personality related:
- // Check if we can buy our favorite weapon
- if (pBot->hasFavoriteSecondaryWeaponPreference()) {
- pBot->rprint("BotDecideWhatToBuy()", "I have a secondary weapon preference");
-
- if (!pBot->ownsFavoriteSecondaryWeapon()) {
- pBot->rprint("BotDecideWhatToBuy()", "I do not own my secondary weapon preference");
-
- if (GoodWeaponForTeam(pBot->ipFavoSecWeapon, pBot->iTeam)) {
- if (pBot->canAfford(pBot->ipFavoSecWeapon)) {
- pBot->rprint("BotDecideWhatToBuy()", "I can afford my favorite secondary weapon, buying it now");
- // Buy favorite weapon
- buy_weapon = pBot->ipFavoPriWeapon;
- } else {
- pBot->rprint("BotDecideWhatToBuy()", "I cannot afford my favorite secondary weapon");
-
- // do not buy a random secondary weapon - rather save money for it.
- // We do here something to 'save' for our favorite weapon
- if (RANDOM_LONG(0, 100) < pBot->ipSaveForWeapon) { // 31.08.04 Frashman forgotten brace
- pBot->rprint("I have decided to save money for my favorite secondary weapon");
- pBot->buy_secondary = false; // don't buy a secondary
- return; // get out of function, don't buy anything
- }
- }
+ if (pBot->hasFavoriteSecondaryWeaponPreference()) {
+ if (!pBot->ownsFavoriteSecondaryWeapon()) {
+ if (GoodWeaponForTeam(pBot->ipFavoSecWeapon, pBot->iTeam)) {
+ if (pBot->canAfford(pBot->ipFavoSecWeapon)) {
+ return pBot->ipFavoSecWeapon;
+ }
+ if (RANDOM_LONG(0, 100) < pBot->ipSaveForWeapon) {
+ return -2; // Stop buying
}
- } else {
- pBot->rprint("BotDecideWhatToBuy()", "I already own my favorite secondary weapon");
- // we already own it, do nothing
- return;
}
}
+ else {
+ return -2; // Stop buying
+ }
+ }
- // no weapon choosen to buy yet - and no preference
- if (buy_weapon < 0) {
- pBot->rprint("BotDecideWhatToBuy()", "Deciding which secondary weapon to buy");
- // Buy secondary
- // Find weapon we can buy in the list of weapons
- for (int i = 0; i < MAX_WEAPONS; i++) {
+ for (const weapon_price_table& i : weapons_table) {
+ if (UTIL_GiveWeaponType(i.iId) != SECONDARY)
+ continue;
- // When enough money and the priority is high enough..
- // Filter out Secondary and Grenades
- if (UTIL_GiveWeaponType(weapons_table[i].iId) != SECONDARY)
- continue;
+ if (!GoodWeaponForTeam(i.iId, team))
+ continue;
- if (GoodWeaponForTeam(weapons_table[i].iId, team) == false)
+ if (i.price <= money) {
+ if (pBot->iSecondaryWeapon > -1) {
+ const int index = weapons_table[pBot->iSecondaryWeapon].iIdIndex;
+ if (weapons_table[index].priority >= i.priority)
continue;
+ }
- if (weapons_table[i].price <= money) {
- if (pBot->iSecondaryWeapon > -1) {
- int index =
- weapons_table[pBot->iSecondaryWeapon].iIdIndex;
- // 31.08.04 Frashman > corrected to >= ,
- // else the bot will buy another weapon with the same priority
- if (weapons_table[index].priority >=
- weapons_table[i].priority)
- continue;
- }
-
- if (buy_weapon == -1)
- buy_weapon = weapons_table[i].iId;
- else {
- if (RANDOM_LONG(0, 100) < weapons_table[i].priority)
- buy_weapon = weapons_table[i].iId;
- }
- if (RANDOM_LONG(0, 100) < weapons_table[i].priority)
- break;
+ if (buy_weapon == -1) {
+ buy_weapon = i.iId;
+ }
+ else {
+ if (RANDOM_LONG(0, 100) < i.priority) {
+ buy_weapon = i.iId;
}
}
+ if (RANDOM_LONG(0, 100) < i.priority)
+ break;
}
+ }
+ return buy_weapon;
+}
- pBot->buy_secondary = false;
-
- // found a secondary weapon to buy
- if (buy_weapon != -1) {
- pBot->rprint("Found a secondary weapon to buy");
- }
- } else if (pBot->buy_ammo_primary == true) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_ammo_primary");
- // Buy primary ammo
- BotPrepareConsoleCommandsToBuyWeapon(pBot, "6", NULL);
- pBot->buy_ammo_primary = false;
- return;
+int BotBuyEquipment(cBot *pBot) {
+ const int money = pBot->bot_money;
- } else if (pBot->buy_ammo_secondary == true) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_ammo_secondary");
- // Buy secondary ammo
- BotPrepareConsoleCommandsToBuyWeapon(pBot, "7", NULL);
- pBot->buy_ammo_secondary = false;
- return;
- } else if (pBot->buy_defusekit) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_defusekit");
+ if (pBot->buy_defusekit) {
pBot->buy_defusekit = false;
- if (money >= 200) {
- buy_weapon = CS_DEFUSEKIT;
- }
- } else if (pBot->buy_armor) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_armor");
- if (money < 1000 && money >= 650) {
- // Buy light armor
- buy_weapon = CS_WEAPON_ARMOR_LIGHT;
- } else if (money >= 1000) {
- // Buy heavy armor
- buy_weapon = CS_WEAPON_ARMOR_HEAVY;
- }
+ if (money >= 200) return CS_DEFUSEKIT;
+ }
+
+ if (pBot->buy_armor) {
pBot->buy_armor = false;
- } else if (pBot->buy_grenade) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_grenade");
- // Buy grenade
- if (money >= weapons_table[ListIdWeapon(CS_WEAPON_HEGRENADE)].price) {
- buy_weapon = CS_WEAPON_HEGRENADE;
- }
+ if (money >= 1000) return CS_WEAPON_ARMOR_HEAVY;
+ if (money >= 650) return CS_WEAPON_ARMOR_LIGHT;
+ }
+ if (pBot->buy_grenade) {
pBot->buy_grenade = false;
- } else if (pBot->buy_flashbang > 0) {
- pBot->rprint("BotDecideWhatToBuy()", "buy_flashbang");
- // Buy flashbang
+ if (money >= weapons_table[ListIdWeapon(CS_WEAPON_HEGRENADE)].price) return CS_WEAPON_HEGRENADE;
+ }
+
+ if (pBot->buy_flashbang > 0) {
if (money >= weapons_table[ListIdWeapon(CS_WEAPON_FLASHBANG)].price) {
- buy_weapon = CS_WEAPON_FLASHBANG;
pBot->buy_flashbang--;
- } else {
- pBot->buy_flashbang = 0; // do not buy
- }
- } else if (pBot->buy_smokegrenade) //31.08.04 Frashman added Smoke Grenade support
- {
- pBot->rprint("BotDecideWhatToBuy()", "buy_smokegrenade");
- // Buy SmokeGrenade
- if (money >= weapons_table[ListIdWeapon(CS_WEAPON_SMOKEGRENADE)].price) {
- buy_weapon = CS_WEAPON_SMOKEGRENADE;
+ return CS_WEAPON_FLASHBANG;
}
+ pBot->buy_flashbang = 0;
+ }
+ if (pBot->buy_smokegrenade) {
pBot->buy_smokegrenade = false;
+ if (money >= weapons_table[ListIdWeapon(CS_WEAPON_SMOKEGRENADE)].price) return CS_WEAPON_SMOKEGRENADE;
+ }
+
+ return -1;
+}
+
+
+/*
+ BotDecideWhatToBuy()
+
+ In this function the bot will choose what weapon to buy from the table.
+ */
+void BotDecideWhatToBuy(cBot *pBot) {
+ const int money = pBot->bot_money;
+ int buy_weapon;
+
+ if (pBot->buy_primary) {
+ buy_weapon = BotBuyPrimaryWeapon(pBot);
+ pBot->buy_primary = false;
+
+ if (buy_weapon == -2) return; // Stop buying
+
+ if (buy_weapon != -1) {
+ const int iMoneyLeft = money - PriceWeapon(buy_weapon);
+ if (iMoneyLeft >= 600 && (RANDOM_LONG(0, 100) < 15 || pBot->iPrimaryWeapon == CS_WEAPON_SHIELD)) {
+ pBot->buy_secondary = true;
+ }
+ }
+ }
+ else if (pBot->buy_secondary) {
+ buy_weapon = BotBuySecondaryWeapon(pBot);
+ pBot->buy_secondary = false;
+ if (buy_weapon == -2) return;
+ }
+ else if (pBot->buy_ammo_primary) {
+ BotPrepareConsoleCommandsToBuyWeapon(pBot, "6", nullptr);
+ pBot->buy_ammo_primary = false;
+ return;
+ }
+ else if (pBot->buy_ammo_secondary) {
+ BotPrepareConsoleCommandsToBuyWeapon(pBot, "7", nullptr);
+ pBot->buy_ammo_secondary = false;
+ return;
+ }
+ else {
+ buy_weapon = BotBuyEquipment(pBot);
}
// Perform the actual buy commands to acquire weapon
- pBot->performBuyActions(buy_weapon);
+ if (buy_weapon != -1) {
+ pBot->performBuyActions(buy_weapon);
+ }
}
/*
@@ -442,7 +338,7 @@ void ConsoleThink(cBot *pBot) {
// buy time is in minutes, we need
// gpGlobals->time is in seconds, so we need to translate the minutes into seconds
- float buyTime = CVAR_GET_FLOAT("mp_buytime") * 60;
+ const float buyTime = CVAR_GET_FLOAT("mp_buytime") * 60;
if (Game.getRoundStartedTime() + buyTime > gpGlobals->time &&
pBot->wantsToBuyStuff()) {
BotDecideWhatToBuy(pBot);
@@ -467,33 +363,32 @@ void BotConsole(cBot *pBot) {
// Here the bot will excecute the console commands if the console counter has been set/changed
if (pBot->console_nr != 0 && pBot->f_console_timer < gpGlobals->time) {
// safety net
- if (pBot->console_nr < 0)
- pBot->console_nr = 0; // Set it to 0
+ pBot->console_nr = std::max(pBot->console_nr, 0); // Set it to 0
// issue command (buy/radio)
if (pBot->console_nr == 1)
- FakeClientCommand(pBot->pEdict, pBot->arg1, NULL, NULL);
+ FakeClientCommand(pBot->pEdict, pBot->arg1, nullptr, nullptr);
// do menuselect
if (pBot->console_nr == 2)
- FakeClientCommand(pBot->pEdict, "menuselect", pBot->arg2, NULL);
+ FakeClientCommand(pBot->pEdict, "menuselect", pBot->arg2, nullptr);
// do menuselect
if (pBot->console_nr == 3) {
// When the last parameter is not null, we will perform that action.
if (pBot->arg3[0] != 0)
FakeClientCommand(pBot->pEdict, "menuselect", pBot->arg3,
- NULL);
+ nullptr);
// reset
pBot->console_nr = -1;
- pBot->f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.2, 0.5);
+ pBot->f_console_timer = gpGlobals->time + RANDOM_FLOAT(0.2f, 0.5f);
}
if (pBot->console_nr > 0)
pBot->console_nr++; // Increase command
- return;
+ //return;
}
} // BotConsole()
diff --git a/bot_client.cpp b/bot_client.cpp
index 3bc1c71..3c91511 100644
--- a/bot_client.cpp
+++ b/bot_client.cpp
@@ -1,3 +1,5 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check it.
+// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
/**
* RealBot : Artificial Intelligence
* Version : Work In Progress
@@ -27,8 +29,9 @@
*
**/
-
-#include
+#include
+#include
+#include
#include
#include
#include
@@ -56,18 +59,18 @@ bot_weapon_t weapon_defs[MAX_WEAPONS]; // array of weapon definitions
static FILE *fp;
// This message is sent when the Counter-Strike VGUI menu is displayed.
-void BotClient_CS_VGUI(void *p, int bot_index) {
+void BotClient_CS_VGUI(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_VGUI()\n");
- if ((*(int *) p) == 2) // is it a team select menu?
+ if (*static_cast(p) == 2) // is it a team select menu?
bots[bot_index].start_action = MSG_CS_TEAM_SELECT;
- else if ((*(int *) p) == 26) // is is a terrorist model select menu?
+ else if (*static_cast(p) == 26) // is is a terrorist model select menu?
bots[bot_index].start_action = MSG_CS_T_SELECT;
- else if ((*(int *) p) == 27) // is is a counter-terrorist model select menu?
+ else if (*static_cast(p) == 27) // is is a counter-terrorist model select menu?
bots[bot_index].start_action = MSG_CS_CT_SELECT;
}
// This message is sent when a menu is being displayed in Counter-Strike.
-void BotClient_CS_ShowMenu(void *p, int bot_index) {
+void BotClient_CS_ShowMenu(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_ShowMenu()\n");
static int state = 0; // current state machine state
@@ -76,18 +79,18 @@ void BotClient_CS_ShowMenu(void *p, int bot_index) {
return;
}
- if (strcmp((char *) p, "#Team_Select") == 0 ||
- strcmp((char *) p, "#Team_Select_Spect") == 0 ||
- strcmp((char *) p, "#IG_Team_Select_Spect") == 0 ||
- strcmp((char *) p, "#IG_Team_Select") == 0 ||
- strcmp((char *) p, "#IG_VIP_Team_Select") == 0 ||
- strcmp((char *) p, "#IG_VIP_Team_Select_Spect") == 0) {
+ if (std::strcmp(static_cast(p), "#Team_Select") == 0 ||
+ std::strcmp(static_cast(p), "#Team_Select_Spect") == 0 ||
+ std::strcmp(static_cast(p), "#IG_Team_Select_Spect") == 0 ||
+ std::strcmp(static_cast(p), "#IG_Team_Select") == 0 ||
+ std::strcmp(static_cast(p), "#IG_VIP_Team_Select") == 0 ||
+ std::strcmp(static_cast(p), "#IG_VIP_Team_Select_Spect") == 0) {
// team select menu?
bots[bot_index].start_action = MSG_CS_TEAM_SELECT;
- } else if (strcmp((char *) p, "#Terrorist_Select") == 0) {
+ } else if (std::strcmp(static_cast(p), "#Terrorist_Select") == 0) {
// T model select?
bots[bot_index].start_action = MSG_CS_T_SELECT;
- } else if (strcmp((char *) p, "#CT_Select") == 0) {
+ } else if (std::strcmp(static_cast(p), "#CT_Select") == 0) {
// CT model select menu?
bots[bot_index].start_action = MSG_CS_CT_SELECT;
}
@@ -104,32 +107,32 @@ void BotClient_Valve_WeaponList(void *p, int bot_index) {
if (state == 0) {
state++;
- strcpy(bot_weapon.szClassname, (char *) p);
+ std::strcpy(bot_weapon.szClassname, static_cast(p));
} else if (state == 1) {
state++;
- bot_weapon.iAmmo1 = *(int *) p; // ammo index 1
+ bot_weapon.iAmmo1 = *static_cast(p); // ammo index 1
} else if (state == 2) {
state++;
- bot_weapon.iAmmo1Max = *(int *) p; // max ammo1
+ bot_weapon.iAmmo1Max = *static_cast(p); // max ammo1
} else if (state == 3) {
state++;
- bot_weapon.iAmmo2 = *(int *) p; // ammo index 2
+ bot_weapon.iAmmo2 = *static_cast(p); // ammo index 2
} else if (state == 4) {
state++;
- bot_weapon.iAmmo2Max = *(int *) p; // max ammo2
+ bot_weapon.iAmmo2Max = *static_cast(p); // max ammo2
} else if (state == 5) {
state++;
- bot_weapon.iSlot = *(int *) p; // slot for this weapon
+ bot_weapon.iSlot = *static_cast(p); // slot for this weapon
} else if (state == 6) {
state++;
- bot_weapon.iPosition = *(int *) p; // position in slot
+ bot_weapon.iPosition = *static_cast(p); // position in slot
} else if (state == 7) {
state++;
- bot_weapon.iId = *(int *) p; // weapon ID
+ bot_weapon.iId = *static_cast(p); // weapon ID
} else if (state == 8) {
state = 0;
- bot_weapon.iFlags = *(int *) p; // flags for weapon (WTF???)
+ bot_weapon.iFlags = *static_cast(p); // flags for weapon (WTF???)
// store away this weapon with it's ammo information...
weapon_defs[bot_weapon.iId] = bot_weapon;
@@ -150,19 +153,19 @@ void BotClient_Valve_WeaponList(void *p, int bot_index) {
}
}
-void BotClient_CS_WeaponList(void *p, int bot_index) {
+void BotClient_CS_WeaponList(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_WeaponList()\n");
// this is just like the Valve Weapon List message
BotClient_Valve_WeaponList(p, bot_index);
}
-void BotClient_Gearbox_WeaponList(void *p, int bot_index) {
+void BotClient_Gearbox_WeaponList(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_WeaponList()\n");
// this is just like the Valve Weapon List message
BotClient_Valve_WeaponList(p, bot_index);
}
-void BotClient_FLF_WeaponList(void *p, int bot_index) {
+void BotClient_FLF_WeaponList(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_WeaponList()\n");
// this is just like the Valve Weapon List message
BotClient_Valve_WeaponList(p, bot_index);
@@ -170,25 +173,25 @@ void BotClient_FLF_WeaponList(void *p, int bot_index) {
// This message is sent when a weapon is selected (either by the bot chosing
// a weapon or by the server auto assigning the bot a weapon).
-void BotClient_Valve_CurrentWeapon(void *p, int bot_index) {
+void BotClient_Valve_CurrentWeapon(void *p, const int bot_index) {
static int state = 0; // current state machine state
static int iState;
static int iId;
- static int iClip;
if (state == 0) {
state++;
- iState = *(int *) p; // state of the current weapon
+ iState = *static_cast(p); // state of the current weapon
} else if (state == 1) {
state++;
- iId = *(int *) p; // weapon ID of current weapon
+ iId = *static_cast(p); // weapon ID of current weapon
} else if (state == 2) {
- state = 0;
+ static int iClip;
+ state = 0;
- iClip = *(int *) p; // ammo currently in the clip for this weapon
+ iClip = *static_cast(p); // ammo currently in the clip for this weapon
- if (iId <= 31) {
- bots[bot_index].bot_weapons |= (1 << iId); // set this weapon bit
+ if (iId < static_cast(std::size(weapon_defs))) {
+ bots[bot_index].bot_weapons |= 1 << iId; // set this weapon bit
if (iState == 1) {
bots[bot_index].current_weapon.iId = iId; // weapon id
@@ -205,46 +208,44 @@ void BotClient_Valve_CurrentWeapon(void *p, int bot_index) {
}
}
}
-
}
-void BotClient_CS_CurrentWeapon(void *p, int bot_index) {
+void BotClient_CS_CurrentWeapon(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_CurrentWeapon()\n");
// this is just like the Valve Current Weapon message
BotClient_Valve_CurrentWeapon(p, bot_index);
}
-void BotClient_Gearbox_CurrentWeapon(void *p, int bot_index) {
+void BotClient_Gearbox_CurrentWeapon(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_CurrentWeapon()\n");
// this is just like the Valve Current Weapon message
BotClient_Valve_CurrentWeapon(p, bot_index);
}
-void BotClient_FLF_CurrentWeapon(void *p, int bot_index) {
+void BotClient_FLF_CurrentWeapon(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_CurrentWeapon()\n");
// this is just like the Valve Current Weapon message
BotClient_Valve_CurrentWeapon(p, bot_index);
}
// This message is sent whenever ammo ammounts are adjusted (up or down).
-void BotClient_Valve_AmmoX(void *p, int bot_index) {
+void BotClient_Valve_AmmoX(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Valve_AmmoX()\n");
static int state = 0; // current state machine state
static int index;
- static int ammount;
- int ammo_index;
if (state == 0) {
state++;
- index = *(int *) p; // ammo index (for type of ammo)
+ index = *static_cast(p); // ammo index (for type of ammo)
} else if (state == 1) {
- state = 0;
+ static int ammount;
+ state = 0;
- ammount = *(int *) p; // the ammount of ammo currently available
+ ammount = *static_cast(p); // the ammount of ammo currently available
bots[bot_index].m_rgAmmo[index] = ammount; // store it away
- ammo_index = bots[bot_index].current_weapon.iId;
+ const int ammo_index = bots[bot_index].current_weapon.iId;
// update the ammo counts for this weapon...
bots[bot_index].current_weapon.iAmmo1 =
@@ -256,19 +257,19 @@ void BotClient_Valve_AmmoX(void *p, int bot_index) {
}
}
-void BotClient_CS_AmmoX(void *p, int bot_index) {
+void BotClient_CS_AmmoX(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_AmmoX()\n");
// this is just like the Valve AmmoX message
BotClient_Valve_AmmoX(p, bot_index);
}
-void BotClient_Gearbox_AmmoX(void *p, int bot_index) {
+void BotClient_Gearbox_AmmoX(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_AmmoX()\n");
// this is just like the Valve AmmoX message
BotClient_Valve_AmmoX(p, bot_index);
}
-void BotClient_FLF_AmmoX(void *p, int bot_index) {
+void BotClient_FLF_AmmoX(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_AmmoX()\n");
// this is just like the Valve AmmoX message
BotClient_Valve_AmmoX(p, bot_index);
@@ -278,24 +279,23 @@ void BotClient_FLF_AmmoX(void *p, int bot_index) {
// also sent so this message is probably not really necessary except it
// allows the HUD to draw pictures of ammo that have been picked up. The
// bots don't really need pictures since they don't have any eyes anyway.
-void BotClient_Valve_AmmoPickup(void *p, int bot_index) {
+void BotClient_Valve_AmmoPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Valve_AmmoPickup()\n");
static int state = 0; // current state machine state
static int index;
- static int ammount;
- int ammo_index;
if (state == 0) {
state++;
- index = *(int *) p;
+ index = *static_cast(p);
} else if (state == 1) {
- state = 0;
+ static int ammount;
+ state = 0;
- ammount = *(int *) p;
+ ammount = *static_cast(p);
bots[bot_index].m_rgAmmo[index] = ammount;
- ammo_index = bots[bot_index].current_weapon.iId;
+ const int ammo_index = bots[bot_index].current_weapon.iId;
// update the ammo counts for this weapon...
bots[bot_index].current_weapon.iAmmo1 =
@@ -305,48 +305,45 @@ void BotClient_Valve_AmmoPickup(void *p, int bot_index) {
}
}
-void BotClient_CS_AmmoPickup(void *p, int bot_index) {
+void BotClient_CS_AmmoPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_AmmoPickup()\n");
// this is just like the Valve Ammo Pickup message
BotClient_Valve_AmmoPickup(p, bot_index);
}
-void BotClient_Gearbox_AmmoPickup(void *p, int bot_index) {
+void BotClient_Gearbox_AmmoPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_AmmoPickup()\n");
// this is just like the Valve Ammo Pickup message
BotClient_Valve_AmmoPickup(p, bot_index);
}
-void BotClient_FLF_AmmoPickup(void *p, int bot_index) {
+void BotClient_FLF_AmmoPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_AmmoPickup()\n");
// this is just like the Valve Ammo Pickup message
BotClient_Valve_AmmoPickup(p, bot_index);
}
// This message gets sent when the bot picks up a weapon.
-void BotClient_Valve_WeaponPickup(void *p, int bot_index) {
- //DebugOut("bot_client: BotClient_Valve_WeaponPickup()\n");
- int index;
-
- index = *(int *) p;
+void BotClient_Valve_WeaponPickup(void *p, const int bot_index) {
+ const int index = *static_cast(p);
// set this weapon bit to indicate that we are carrying this weapon
bots[bot_index].bot_weapons |= (1 << index);
}
-void BotClient_CS_WeaponPickup(void *p, int bot_index) {
+void BotClient_CS_WeaponPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_WeaponPickup()\n");
// this is just like the Valve Weapon Pickup message
BotClient_Valve_WeaponPickup(p, bot_index);
}
-void BotClient_Gearbox_WeaponPickup(void *p, int bot_index) {
+void BotClient_Gearbox_WeaponPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_WeaponPickup()\n");
// this is just like the Valve Weapon Pickup message
BotClient_Valve_WeaponPickup(p, bot_index);
}
-void BotClient_FLF_WeaponPickup(void *p, int bot_index) {
+void BotClient_FLF_WeaponPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_WeaponPickup()\n");
// this is just like the Valve Weapon Pickup message
BotClient_Valve_WeaponPickup(p, bot_index);
@@ -358,74 +355,74 @@ void BotClient_Valve_ItemPickup(void *p, int bot_index) {
//DebugOut("bot_client: BotClient_Valve_ItemPickup()\n");
}
-void BotClient_CS_ItemPickup(void *p, int bot_index) {
+void BotClient_CS_ItemPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_ItemPickup()\n");
// this is just like the Valve Item Pickup message
BotClient_Valve_ItemPickup(p, bot_index);
}
-void BotClient_Gearbox_ItemPickup(void *p, int bot_index) {
+void BotClient_Gearbox_ItemPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_ItemPickup()\n");
// this is just like the Valve Item Pickup message
BotClient_Valve_ItemPickup(p, bot_index);
}
-void BotClient_FLF_ItemPickup(void *p, int bot_index) {
+void BotClient_FLF_ItemPickup(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_ItemPickup()\n");
// this is just like the Valve Item Pickup message
BotClient_Valve_ItemPickup(p, bot_index);
}
// This message gets sent when the bots health changes.
-void BotClient_Valve_Health(void *p, int bot_index) {
+void BotClient_Valve_Health(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Valve_Health()\n");
- bots[bot_index].bot_health = *(int *) p; // health ammount
+ bots[bot_index].bot_health = *static_cast(p); // health ammount
}
-void BotClient_CS_Health(void *p, int bot_index) {
+void BotClient_CS_Health(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_Health()\n");
// this is just like the Valve Health message
BotClient_Valve_Health(p, bot_index);
}
-void BotClient_Gearbox_Health(void *p, int bot_index) {
+void BotClient_Gearbox_Health(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_Health()\n");
// this is just like the Valve Health message
BotClient_Valve_Health(p, bot_index);
}
-void BotClient_FLF_Health(void *p, int bot_index) {
+void BotClient_FLF_Health(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_Health()\n");
// this is just like the Valve Health message
BotClient_Valve_Health(p, bot_index);
}
// This message gets sent when the bots armor changes.
-void BotClient_Valve_Battery(void *p, int bot_index) {
+void BotClient_Valve_Battery(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Valve_Battery()\n");
- bots[bot_index].bot_armor = *(int *) p; // armor ammount
+ bots[bot_index].bot_armor = *static_cast(p); // armor ammount
}
-void BotClient_CS_Battery(void *p, int bot_index) {
+void BotClient_CS_Battery(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_Battery()\n");
// this is just like the Valve Battery message
BotClient_Valve_Battery(p, bot_index);
}
-void BotClient_Gearbox_Battery(void *p, int bot_index) {
+void BotClient_Gearbox_Battery(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_Battery()\n");
// this is just like the Valve Battery message
BotClient_Valve_Battery(p, bot_index);
}
-void BotClient_FLF_Battery(void *p, int bot_index) {
+void BotClient_FLF_Battery(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_Battery()\n");
// this is just like the Valve Battery message
BotClient_Valve_Battery(p, bot_index);
}
// This message gets sent when the bots are getting damaged.
-void BotClient_Valve_Damage(void *p, int bot_index) {
+void BotClient_Valve_Damage(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Valve_Damage()\n");
static int state = 0; // current state machine state
static int damage_armor;
@@ -435,24 +432,24 @@ void BotClient_Valve_Damage(void *p, int bot_index) {
if (state == 0) {
state++;
- damage_armor = *(int *) p;
+ damage_armor = *static_cast(p);
} else if (state == 1) {
state++;
- damage_taken = *(int *) p;
+ damage_taken = *static_cast(p);
} else if (state == 2) {
state++;
- damage_bits = *(int *) p;
+ damage_bits = *static_cast(p);
} else if (state == 3) {
state++;
- damage_origin.x = *(float *) p;
+ damage_origin.x = *static_cast(p);
} else if (state == 4) {
state++;
- damage_origin.y = *(float *) p;
+ damage_origin.y = *static_cast(p);
} else if (state == 5) {
state = 0;
- damage_origin.z = *(float *) p;
- if ((damage_armor > 0) || (damage_taken > 0)) {
+ damage_origin.z = *static_cast(p);
+ if (damage_armor > 0 || damage_taken > 0) {
// Damage recieved:
// - when the prev node was higher (so we are sure we do FIX the correct nodes!)
@@ -462,13 +459,13 @@ void BotClient_Valve_Damage(void *p, int bot_index) {
if (damage_bits & (DMG_FALL | DMG_CRUSH)) {
pBot->rprint_trace("BotClient_Valve_Damage", "Taken fall damage!");
if (pBot->getPathIndex() > 0) { // was one node further, so we can use previous node!
- int iNode = NodeMachine.getNodeIndexFromBotForPath(pBot->iBotIndex, pBot->getPreviousPathIndex());
+ const int iNode = NodeMachine.getNodeIndexFromBotForPath(pBot->iBotIndex, pBot->getPreviousPathIndex());
- float fDist = fabs(damage_origin.z - NodeMachine.node_vector(iNode).z);
+ const float fDist = std::fabs(damage_origin.z - NodeMachine.node_vector(iNode).z);
if (fDist > 90) {
// we know where we came from, and we know where we went to
- int iNodeTo = NodeMachine.getNodeIndexFromBotForPath(pBot->iBotIndex,
- pBot->getPathIndex());
+ const int iNodeTo = NodeMachine.getNodeIndexFromBotForPath(pBot->iBotIndex,
+ pBot->getPathIndex());
// remove connection?
@@ -484,7 +481,7 @@ void BotClient_Valve_Damage(void *p, int bot_index) {
return;
// depending on bot skill slow this bot down a bit
-// pBot->f_move_speed *= (((10 - pBot->bot_skill) + 1) / 10);
+ // pBot->f_move_speed *= (((10 - pBot->bot_skill) + 1) / 10);
// if the bot doesn't have an enemy and someone is shooting at it then
// turn in the attacker's direction...
@@ -492,7 +489,7 @@ void BotClient_Valve_Damage(void *p, int bot_index) {
// face the attacker...
edict_t *damageInflictor = pBot->pEdict->v.dmg_inflictor;
if (damageInflictor) {
- if (strcmp(STRING(damageInflictor->v.classname), "player") == 0) {
+ if (std::strcmp(STRING(damageInflictor->v.classname), "player") == 0) {
// Face danger vector
pBot->vHead = damage_origin;
pBot->vBody = damage_origin;
@@ -502,7 +499,7 @@ void BotClient_Valve_Damage(void *p, int bot_index) {
pBot->rprint("BotClient_Valve_Damage", "Damage taken, by player, change goal to damage origin.");
char msg[255];
- sprintf(msg, "damage_origin (x,y,z) => (%f,%f,%f) | damageInflictor->v.origin (x,y,z) => (%f,%f,%f)",
+ snprintf(msg, sizeof(msg), "damage_origin (x,y,z) => (%f,%f,%f) | damageInflictor->v.origin (x,y,z) => (%f,%f,%f)",
damage_origin.x,
damage_origin.y,
damage_origin.z,
@@ -518,7 +515,7 @@ void BotClient_Valve_Damage(void *p, int bot_index) {
pBot->forgetPath();
} else {
char msg[255];
- sprintf(msg, "I have a damage inflictor! -> %s", STRING(damageInflictor->v.classname));
+ snprintf(msg, sizeof(msg), "I have a damage inflictor! -> %s", STRING(damageInflictor->v.classname));
pBot->rprint("BotClient_Valve_Damage", msg);
}
} else {
@@ -531,13 +528,14 @@ void BotClient_Valve_Damage(void *p, int bot_index) {
}
}
-void BotClient_CS_Damage(void *p, int bot_index) {
+void BotClient_CS_Damage(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_Damage()\n");
// this is just like the Valve Battery message
BotClient_Valve_Damage(p, bot_index);
}
-void BotClient_Gearbox_Damage(void *p, int bot_index) {
+// Not required? [APG]RoboCop[CL]
+/*void BotClient_Gearbox_Damage(void* p, int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_Damage()\n");
// this is just like the Valve Battery message
BotClient_Valve_Damage(p, bot_index);
@@ -547,10 +545,10 @@ void BotClient_FLF_Damage(void *p, int bot_index) {
//DebugOut("bot_client: BotClient_FLF_Damage()\n");
// this is just like the Valve Battery message
BotClient_Valve_Damage(p, bot_index);
-}
+}*/
-void BotClient_CS_SayText(void *p, int bot_index) {
+void BotClient_CS_SayText(void *p, const int bot_index) {
static unsigned char ucEntIndex;
/**
@@ -566,36 +564,37 @@ void BotClient_CS_SayText(void *p, int bot_index) {
// handling of this "SayText" thingy.
if (counterstrike == 0) {
if (state == 0) {
- ucEntIndex = *(unsigned char *) p;
+ ucEntIndex = *static_cast(p);
} else if (state == 1) {
- cBot *pBot = &bots[bot_index];
+ const cBot *pBot = &bots[bot_index];
if (ENTINDEX(pBot->pEdict) != ucEntIndex) {
char sentence[MAX_SENTENCE_LENGTH];
char chSentence[MAX_SENTENCE_LENGTH];
char netname[30];
- memset(sentence, 0, sizeof(sentence));
- memset(chSentence, 0, sizeof(chSentence));
- memset(netname, 0, sizeof(netname));
+ std::memset(sentence, 0, sizeof(sentence));
+ std::memset(chSentence, 0, sizeof(chSentence));
+ std::memset(netname, 0, sizeof(netname));
- strcpy(sentence, (char *) p); // the actual sentence
+ std::strcpy(sentence, static_cast(p)); // the actual sentence
- int length = 0;
+ unsigned int length = 0;
// FIXED: In any case that this might return NULL, do not crash the server
- if (strstr(sentence, " : "))
- length = strlen(sentence) - strlen(strstr(sentence, " : "));
+ const char* found = std::strstr(sentence, " : ");
+ if (found != nullptr)
+ length = std::strlen(sentence) - std::strlen(found);
- int tc = 0, c;
+ int tc = 0;
- for (c = length; c < MAX_SENTENCE_LENGTH; c++) {
+ for (unsigned int c = length; c < MAX_SENTENCE_LENGTH; c++) {
chSentence[tc] = sentence[c];
tc++;
}
- edict_t *pPlayer = INDEXENT(ucEntIndex);
- strcpy(netname, STRING(pPlayer->v.netname));
+ const edict_t *pPlayer = INDEXENT(ucEntIndex);
+ std::strcpy(netname, STRING(pPlayer->v.netname));
ChatEngine.set_sentence(netname, chSentence);
state = -1;
@@ -605,15 +604,22 @@ void BotClient_CS_SayText(void *p, int bot_index) {
// CS 1.6
if (state == 0) {
// who sent this message?
- ucEntIndex = *(unsigned char *) p;
+ ucEntIndex = *static_cast(p);
}
// to who?
else if (state == 1) {
// here must be some team check so we do not let bots
// of the other team react to this somehow..
- // - after playing with the dll i did not notice any weird stuff yet...
- // - so only when people discover some bugs with this we are going to fix this
- // - thing... ie "Only fix it when its broken".
+ edict_t* pPlayer = INDEXENT(ucEntIndex);
+ if (pPlayer)
+ {
+ const cBot* pBot = &bots[bot_index];
+ if (UTIL_GetTeam(pPlayer) != pBot->iTeam - 1)
+ {
+ // message is from another team, don't process it
+ state = -1; // reset state machine
+ }
+ }
}
// don't know?
else if (state == 2) {
@@ -626,15 +632,15 @@ void BotClient_CS_SayText(void *p, int bot_index) {
char netname[30];
// init
- memset(sentence, 0, sizeof(sentence));
- memset(netname, 0, sizeof(netname));
+ std::memset(sentence, 0, sizeof(sentence));
+ std::memset(netname, 0, sizeof(netname));
// copy in memory
- strcpy(sentence, (char *) p);
+ std::strcpy(sentence, static_cast(p));
// copy netname
- edict_t *pPlayer = INDEXENT(ucEntIndex);
- strcpy(netname, STRING(pPlayer->v.netname));
+ const edict_t *pPlayer = INDEXENT(ucEntIndex);
+ std::strcpy(netname, STRING(pPlayer->v.netname));
// and give chatengine something to do
ChatEngine.set_sentence(netname, sentence);
@@ -652,7 +658,7 @@ void BotClient_CS_SayText(void *p, int bot_index) {
// Converted to use switches.
// This message gets sent when the bot enters a buyzone
-void BotClient_CS_StatusIcon(void *p, int bot_index) {
+void BotClient_CS_StatusIcon(void *p, const int bot_index) {
/*
FROM SDK 2.3
// Message handler for StatusIcon message
@@ -664,20 +670,20 @@ void BotClient_CS_StatusIcon(void *p, int bot_index) {
// byte : blue
*/
static int state = 0; // current state machine state
- static int EnableIcon;
- if (p == 0) // A bandaid. Make this whole thing more robust!
+ if (p == nullptr) // A bandaid. Make this whole thing more robust!
{
state = 0;
return;
}
switch (state++) {
- case 0: // Enable or not?
- EnableIcon = *(int *) p; // check the byte
+ static int EnableIcon;
+ case 0: // Enable or not?
+ EnableIcon = *static_cast(p); // check the byte
break;
case 1: // Which icon
- if (strcmp((char *) p, "buyzone") == 0) {
+ if (std::strcmp(static_cast(p), "buyzone") == 0) {
switch (EnableIcon) {
case 0: // Not in buy zone
state = 0;
@@ -687,7 +693,7 @@ void BotClient_CS_StatusIcon(void *p, int bot_index) {
default:
break;
}
- } else if (strcmp((char *) p, "c4") == 0) {
+ } else if (std::strcmp(static_cast(p), "c4") == 0) {
switch (EnableIcon) {
case 0: // No C4
bots[bot_index].bHUD_C4_plantable = false;
@@ -702,7 +708,7 @@ void BotClient_CS_StatusIcon(void *p, int bot_index) {
default:
break;
}
- } else if (strcmp((char *) p, "defuser") == 0) {
+ } else if (std::strcmp(static_cast(p), "defuser") == 0) {
switch (EnableIcon) {
case 0: // No defuser
state = 0;
@@ -712,7 +718,7 @@ void BotClient_CS_StatusIcon(void *p, int bot_index) {
default:
break;
}
- } else if (strcmp((char *) p, "rescue") == 0) {
+ } else if (std::strcmp(static_cast(p), "rescue") == 0) {
switch (EnableIcon) {
case 0: // Not in rescue zone
state = 0;
@@ -742,14 +748,14 @@ void BotClient_CS_StatusIcon(void *p, int bot_index) {
}
// This message gets sent when the bots money ammount changes (for CS)
-void BotClient_CS_Money(void *p, int bot_index) {
+void BotClient_CS_Money(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_Money()\n");
static int state = 0; // current state machine state
if (state == 0) {
state++;
- bots[bot_index].bot_money = *(int *) p; // amount of money
+ bots[bot_index].bot_money = *static_cast(p); // amount of money
} else {
state = 0; // ingore this field
}
@@ -761,17 +767,17 @@ void BotClient_Valve_DeathMsg(void *p, int bot_index) {
static int state = 0; // current state machine state
static int killer_index;
static int victim_index;
- static edict_t *victim_edict;
- static int index;
if (state == 0) {
state++;
- killer_index = *(int *) p; // ENTINDEX() of killer
+ killer_index = *static_cast(p); // ENTINDEX() of killer
} else if (state == 1) {
state++;
- victim_index = *(int *) p; // ENTINDEX() of victim
+ victim_index = *static_cast(p); // ENTINDEX() of victim
} else if (state == 2) {
- state = 0;
+ static int index;
+ static edict_t *victim_edict;
+ state = 0;
victim_edict = INDEXENT(victim_index);
@@ -781,7 +787,7 @@ void BotClient_Valve_DeathMsg(void *p, int bot_index) {
if (index != -1) {
if ((killer_index == 0) || (killer_index == victim_index)) {
// bot killed by world (worldspawn) or bot killed self...
- bots[index].killer_edict = NULL;
+ bots[index].killer_edict = nullptr;
} else {
// store edict of player that killed this bot...
bots[index].killer_edict = INDEXENT(killer_index);
@@ -790,64 +796,60 @@ void BotClient_Valve_DeathMsg(void *p, int bot_index) {
}
}
-void BotClient_CS_DeathMsg(void *p, int bot_index) {
+void BotClient_CS_DeathMsg(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_CS_DeathMsg()\n");
// this is just like the Valve DeathMsg message
BotClient_Valve_DeathMsg(p, bot_index);
}
-void BotClient_Gearbox_DeathMsg(void *p, int bot_index) {
+void BotClient_Gearbox_DeathMsg(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Gearbox_DeathMsg()\n");
// this is just like the Valve DeathMsg message
BotClient_Valve_DeathMsg(p, bot_index);
}
-void BotClient_FLF_DeathMsg(void *p, int bot_index) {
+void BotClient_FLF_DeathMsg(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_FLF_DeathMsg()\n");
// this is just like the Valve DeathMsg message
BotClient_Valve_DeathMsg(p, bot_index);
}
-void BotClient_Valve_ScreenFade(void *p, int bot_index) {
+void BotClient_Valve_ScreenFade(void *p, const int bot_index) {
//DebugOut("bot_client: BotClient_Valve_ScreenFade()\n");
static int state = 0; // current state machine state
static int duration;
static int hold_time;
- static int fade_flags;
- float length;
if (state == 0) {
state++;
- duration = *(int *) p;
+ duration = *static_cast(p);
} else if (state == 1) {
state++;
- hold_time = *(int *) p;
+ hold_time = *static_cast(p);
} else if (state == 2) {
- state++;
- fade_flags = *(int *) p;
+ static int fade_flags;
+ state++;
+ fade_flags = *static_cast(p);
} else if (state == 6) {
state = 0;
- length = (duration + hold_time) / 4096.0;
+ float length = (static_cast(duration + hold_time)) / 4096.0f;
int iDevide = bots[bot_index].bot_skill;
- if (iDevide < 1)
- iDevide = 1;
+ iDevide = std::max(iDevide, 1);
- length -= ((10 / iDevide) * 0.5);
+ length -= (static_cast(10) / static_cast